问题
之前在业务上有这样一个场景,通过 script 标签动态引入了一个外部资源,具体方式是这样的
const script = document.createElement('script');script.src = 'xxx';script.async = true;document.body.appendChild(script);复制代码最近发现在某些情况下需要取消这个请求,因此对取消script标签发出的请求的方法进行研究。
取消请求的几种方式
取消 XMLHttpRequest 请求
// 发送请求const xhr = newXMLHttpRequest();xhr.open('GET', url, true);xhr.send();// 1s后取消请求的两种方法// a. 设置超时时间属性,在 IE 中,超时属性可能只能在调用 open()方法之后且在调用 send()方法之前设置。xhr.timeout = 1000;// b. 利用abort方法setTimeout(() => { xhr.abort();}, 1000);复制代码
取消 fetch 请求
fetch请求的取消主要依赖于AbortController对象,当fetch 请求初始化时,我们将 AbortSignal 作为一个选项传递进入请求的选项对象中(下面的 {signal})。
const controller = newAbortController();fetch(url, { signal: controller.signal });// 1s后取消请求setTimeout(() => { controller.abort();}, 1000);复制代码取消 axios 请求
取消 axios 请求同样依赖于 AbortController 对象。
const controller = newAbortController();axios.get(url, { signal: controller.signal });// 1s后取消请求setTimeout(() => { controller.abort();}, 1000);复制代码取消使用script标签
通过对网上的资料进行整理,并没有发现直接取消 script 标签发起的请 求的方法。并且当请求发出后对 script 进行的操作(如删除 dom 节点)也不会造成影响。那么能不能将 script 发起的请求改为使用以上三种方法之一来实现呢?
改为 fetch 方法
我首先尝试了 fetch 方法。通过使用 fetch 方法对网址进行请求,我发现请求得到的类型是一个 ReadableStream 对象。
MDN上提供了一种方法可以获取到 ReadableStream 对象中的内容:
fetch('https://www.example.org') .then((response) => response.body) .then((rb) => { const reader = rb.getReader(); returnnewReadableStream({ start(controller) { // The following function handles each data chunkfunctionpush() { // "done" is a Boolean and value a "Uint8Array" reader.read().then(({ done, value }) => { // If there is no more data to readif (done) { console.log('done', done); controller.close(); return; } // Get the data and send it to the browser via the controller controller.enqueue(value); // Check chunks by logging to the consoleconsole.log(done, value); push(); }); } push(); }, }); }) .then((stream) =>// Respond with our streamnewResponse(stream, { headers: { 'Content-Type': 'text/html' } }).text() ) .then((result) => { // Do things with resultconsole.log(result); });复制代码使用这种方法我就通过 fetch 方法获取到了原来 script 标签请求的内容,也就可以使用 AbortController 来控制请求的取消。
改为 XMLHttpRequest 方法
尝试使用 fetch 方法解决问题之后,我又对 XMLHttpRequest 进行了尝试,发现这种方法更加简便,获取的请求内包含一个 responseText 字段就是我需要的内容,并且在请求未成功或尚未发送的情况下这个值为 null ,也就更方便进行请求是否成功的判断。
结论
对于 script 标签发出的请求我们无法取消,但是我们可以通过其他的方法来达到 script 标签的效果,因为 XMLHttpRequest 已经足够简便,我就没有对 axios 进行尝试,相信也肯定可以达到同样的目标,有兴趣的同学可以尝试一下。