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

【前端】面试题挑战 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
小恐龙
花!
滑稽大佬
演奏
程序员专属
上一篇
下一篇