[星球打卡] JavaScript 中如何中止网络请求?
本文发布于 774 天前,最后更新于 772 天前,其中的信息可能已经有所发展或是发生改变。

【前端】面试题挑战 Day2 JavaScript 中如何中止网络请求? - 编程导航 (code-nav.cn)

const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal }).then(response => {
// Handle the response
}).catch(error => {
if (error.name === 'AbortError') {
console.log('Request was cancelled');
} else {
console.log('Request failed:', error);
}
});
// To abort the request, call the following:
controller.abort();

js 给的 api 让我们可以随时中断一个 fetch 请求,那么,如果我想造轮子实现这个功能该怎么做呢?

Promise

首先能想到的是用一个 Promise,来包装 fetch 返回的 promise,再使用包装的 Promise.reject 方法来实现中断请求

不过函数返回时我使用了 Promise.race 而不直接返回 abortPromise,原因是因为 fetch 可能返回异常,直接返回包装的 promise 则可能产生无法捕获的异常

以下是示例代码

const fetchAbort = (url: string) => {
let res, abort;
const abortPromise = new Promise<Response>((resolve, reject) => {
res = resolve;
abort = reject.bind(this, `Fetch "${url}" has been aborted`);
});
return {
response: Promise.race([fetch(url).then(ret => res(ret)), abortPromise]),
abort
};
};
const { response, abort } = fetchAbort("./serverConfig.json");
abort();
// abort后,response的promise链将catch到fetch abort消息
// 而不会返回fetch返回的消息
response
.then(ret => ret.text())
.then(txt => console.log(txt))
.catch(err => {
console.log(err);
});

输出:

Fetch "./serverConfig.json" has been aborted

代码缺陷也显而易见,这段代码虽然能拦截 fetch 的返回,但是 fetch 占用的网络资源并不会被释放。

也就是说,如果 api 请求还在 pending 状态,控制台 network 列表仍然能看到 fetch 还在请求状态,占用着 io 资源。

所以,如果想要 abort 的同时,释放 fetch 占用的资源,单靠 Promise 是不够的。

XMLHttpRequest.abort()

可以使用 XML 代替 fetch,反正造轮子就是为了绕开 fetch,封装就完了

const fetchAbort = (url: string) => {
let res, abort, xhr;
const xhrPromise = new Promise((resolve, reject) => {
xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (this.status == 200) {
return resolve(this.response);
}
return reject({
xhr: this,
msg: "Error",
status: this.status,
statusText: this.statusText
});
}
};
xhr.open("Get", url);
xhr.send();
});
const abortPromise = new Promise((resolve, reject) => {
res = resolve;
abort = () => {
xhr.abort();
return reject(`Fetch "${url}" has been aborted`);
};
});
return {
response: Promise.race([xhrPromise.then(ret => res(ret)), abortPromise]),
abort
};
};
const { response, abort } = fetchAbort("./serverConfig.json");
abort();
response
.then(ret => console.log(ret))
.catch(err => {
console.log(err);
});

输出:

Fetch "./serverConfig.json" has been aborted

fetch 的原生 abort 代码对比,可以看到请求大小为 0B,说明请求虽然发出去了,但是浏览器直接断开了连接,并没有选择接收。于是实现了一个简单的 fetchAbort

不过封装程度还不够,剩下的轮子就不造了,了解原理才是本次造轮子的目的。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
Source: https://github.com/zhaoolee/ChineseBQB
Source: https://github.com/zhaoolee/ChineseBQB
Source: https://github.com/zhaoolee/ChineseBQB
颜文字
Emoji
小恐龙
花!
滑稽大佬
演奏
程序员专属
上一篇
下一篇