发 帖  
原厂入驻New
[问答]

如何使用abortController终止fetch和promise?

66 abortController
分享
使用abortController 终止fetch和promise的方法


0
2020-11-5 08:07:35   评论 分享淘帖 邀请回答
1个回答
在使用 fetch 和 promise 的时候,中途终止它们是一个很常见的需求,我们来看一看怎么实现。通过本文您可以学到:


  • 怎么在外面终止 xhr 请求
  • abortController 是什么
  • 怎么使用 abortController 终止 fetch 请求
  • 怎么使用 abortController 终止 promise 请求

怎么在外部终止 xhr 请求

我们先来回顾一下怎么在外部终止 xhr 请求:
let xhr = new XMLHttpRequest();xhr.onload = (res) => console.log(res);xhr.onerror = (err) => console.log(err);xhr.onabort = () => console.log('aborted!');xhr.open('get', 'https://slowmo.glitch.me/5000');xhr.send();setTimeout(() => {    xhr.abort();}, 200);AbortController

参考资料:abortController接口
AbortController 接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求。目前这个接口的兼容性是除了IE已经能够兼容所有主流浏览器了。示例如下:
const controller = new AbortController();const signal = controller.signal;signal.addEventListener('abort', () => {    console.log('aborted!');});controller.abort();中止 fetch 请求

fetch 方法的第二个参数可以接收 signal 参数,当被中止时,会 reject 一个名字为 AbortError 的 error 并被 catch 捕捉到,示例如下:
const controller = new AbortController();const signal = controller.signal;fetch('https://slowmo.glitch.me/5000', { signal })    .then(res => res.json())    .then(res => console.log(res))    .catch((err) => {        if (err.name === 'AbortError') {            console.log('aborted');        } else {            console.log('error');        }    });setTimeout(() => {    controller.abort();}, 200);中止 promise

其实不需要 AbortController也可以实现手动中止 promise,还是用那套劫持的方法。示例如下:
class MyPromise {    constructor(executor) {        let abort = null;        let p = new Promise((resovle, reject)=>{            executor(resovle, reject);            abort = err => reject(err);        })        p.abort = abort;        return p;    }}// testlet test = new MyPromise((resolve) => {    setTimeout(() => resolve(1), 200);});// 这里不能直接把 then 和 catch 加到上面的末尾去test.then(res => console.log(res)).catch(err => console.log(err));test.abort('aborted!');上面有一些不完美,就是在初始化 test 的时候,后面不能带上 then 或 catch 方法,因为这些方法返回的是一个 Promise 实例而不是 MyPromise 实例。
使用 AbortController 可以解决这个问题,示例如下:
class MyPromise {    constructor(executor, { signal }) {        return new Promise((resolve, reject)=>{            executor(resolve, reject);            if (signal) {                signal.addEventListener('abort', () => {                    reject('aborted!');                });            }        })    }}// testconst controller = new AbortController();const signal = controller.signal;let test = new MyPromise((resolve) => {    setTimeout(() => resolve(1), 200);}, { signal }).then(res => console.log(res)).catch(err => console.log(err));controller.abort('aborted!');上面两种方案看起来很美好,但是其实并不完美,因为 then 和 catch 方法返回的是一个 Promise 实例而不是 MyPromise 实例,所以目前这个 abort 方法不能中断 then 或 catch 里面的内容,如果要修正的话,需要再继续改写 then 和 catch 方法。
2020-11-5 16:23:48 评论

举报

撰写答案

你正在撰写答案

如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
我要提问
关闭

站长推荐 上一条 /9 下一条

快速回复 返回顶部 返回列表