注册
web

如何取消 script 标签发出的请求

问题


之前在业务上有这样一个场景,通过 script 标签动态引入了一个外部资源,具体方式是这样的


const script = document.createElement('script');
script.src = 'xxx';
script.async = true;
document.body.appendChild(script);

最近发现在某些情况下需要取消这个请求,因此对取消script标签发出的请求的方法进行研究。


取消请求的几种方式


取消 XMLHttpRequest 请求


// 发送请求
const xhr = new XMLHttpRequest();
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 = new AbortController();
fetch(url, { signal: controller.signal });
// 1s后取消请求
setTimeout(() => {
controller.abort();
}, 1000);

取消 axios 请求


取消 axios 请求同样依赖于 AbortController 对象。


const controller = new AbortController();
axios.get(url, { signal: controller.signal });
// 1s后取消请求
setTimeout(() => {
controller.abort();
}, 1000);

取消使用script标签


通过对网上的资料进行整理,并没有发现直接取消 script 标签发起的请
求的方法。并且当请求发出后对 script 进行的操作(如删除 dom 节点)也不会造成影响。那么能不能将 script 发起的请求改为使用以上三种方法之一来实现呢?


改为 fetch 方法


我首先尝试了 fetch 方法。通过使用 fetch 方法对网址进行请求,我发现请求得到的类型是一个 ReadableStream 对象。
image.png
MDN上提供了一种方法可以获取到 ReadableStream 对象中的内容:


fetch('https://www.example.org')
.then((response) => response.body)
.then((rb) => {
const reader = rb.getReader();
return new ReadableStream({
start(controller) {
// The following function handles each data chunk
function push() {
// "done" is a Boolean and value a "Uint8Array"
reader.read().then(({ done, value }) => {
// If there is no more data to read
if (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 console
console.log(done, value);
push();
});
}
push();
},
});
})
.then((stream) =>
// Respond with our stream
new Response(stream, { headers: { 'Content-Type': 'text/html' } }).text()
)
.then((result) => {
// Do things with result
console.log(result);
});

使用这种方法我就通过 fetch 方法获取到了原来 script 标签请求的内容,也就可以使用 AbortController 来控制请求的取消。


改为 XMLHttpRequest 方法


尝试使用 fetch 方法解决问题之后,我又对 XMLHttpRequest 进行了尝试,发现这种方法更加简便,获取的请求内包含一个 responseText 字段就是我需要的内容,并且在请求未成功或尚未发送的情况下这个值为 null ,也就更方便进行请求是否成功的判断。


结论


对于 script 标签发出的请求我们无法取消,但是我们可以通过其他的方法来达到 script 标签的效果,因为 XMLHttpRequest 已经足够简便,我就没有对 axios 进行尝试,相信也肯定可以达到同样的目标,有兴趣的同学可以尝试一下。


作者:Maaarch
来源:juejin.cn/post/7208092574162419770

0 个评论

要回复文章请先登录注册