当前位置:首页 » 《关于电脑》 » 正文

前端如何取消接口调用

27 人参与  2024年09月13日 10:01  分类 : 《关于电脑》  评论

点击全文阅读


?‍? 写在开头
点赞 + 收藏 === 学会???

1. xmlHttpRequest是如何取消请求的?

实例化的XMLHttpRequest对象上也有abort方法

const xhr = new XMLHttpRequest();xhr.addEventListener('load', function(e) {  console.log(this.responseText);});xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');xhr.send();
// 返回{  "userId": 1,  "id": 1,  "title": "delectus aut autem",  "completed": false}

如果在send后直接abort取消

// xhr的取消操作:执行过程比较模糊,不知道abort什么时机进行处理xhr.abort()

如果在定时器中(当定时器的时长那个和接口请求时长差不多)取消请求,会发现资源已经获取到了,但是控制台没有打印
在这里插入图片描述

2. AbortController

const ac = new AbortController();const { signal } = ac;const url = "https://jsonplaceholder.typicode.com/todos/1";​fetch(url, { signal })  .then((res) => res.json())  .then((json) => console.log(json));

直接使用abort取消请求

ac.abort()

在这里插入图片描述
这里报错的原因是没有对错误进行捕获

// 修改后的代码fetch(url, { signal: ac.signal })  .then((res) => res.json())  .then((json) => console.log(json))  .catch(e => console.log(e)) // DOMException: signal is aborted without reasonac.abort() // abort接受一个入参,会被传递到signal的reason属性中

为什么可以这样取消?

fetch监听signal对象的状态,进而可以终止请求

2.1 如何同时取消多个请求?

const ac = new AbortController();const { signal } = ac;const url = "https://jsonplaceholder.typicode.com/todos";​const todoRequest = (id, { signal }) => {  fetch(`${url}/${id}`, { signal })    .then((res) => res.json())    .then((json) => console.log(json))    .catch((e) => console.log(e)); // DOMException: signal is aborted without reason};​todoRequest(1, { signal });todoRequest(2, { signal });todoRequest(3, { signal });​ac.abort("cancled");

在这里插入图片描述

2.2 AbortSignal

是一个接口,用于表示一个信号对象,它允许你与正在执行的异步操作通信,以便可以在操作完成之前将其中止。

2.3 AbortSignal的方法

2.3.1 abort

静态方法,用于创建一个已经中止的 AbortSignal 对象。当你调用这个方法时,它会返回一个带有 aborted 状态为 true 的 AbortSignal 实例。

const signalAbout = AbortSignal.abort(); // AbortSignal {aborted: true, reason: DOMException: signal is aborted without reason...}

2.3.2 throwIfAborted 方法

用于在执行代码之前检查 AbortSignal 是否已经被中止。如果 AbortSignal 已经被中止,它会抛出一个 AbortError。这个方法可以帮助开发者在执行特定操作之前确保没有被中止,以避免不必要的处理。

const signalAbout = AbortSignal.abort('abortedReason');try {    signalAbout.throwIfAborted(); // 抛出error: abortedReason} catch (error) {    console.log(error);}

2.3.3 timeout

用于创建一个在指定时间后自动中止的 AbortSignal 对象。这在需要设置请求超时时非常有用。

// 使用 AbortSignal.timeout 设置 10ms超时const signalAbout = AbortSignal.timeout(10);const todoRequest = (id, { signal }) => {  fetch(`${url}/${id}`, { signal })    .then((res) => res.json())    .then((json) => console.log("json: ", json))    .catch((e) => console.log("err: ", e)); //DOMException: signal timed out };todoRequest(1, { signal: signalAbout });

在这里插入图片描述

2.3.3.1 添加事件监听 => 从没有终止到被终止

AbortSignal继承自EventTarget,因为 AbortSignal 是用来监听 abort 事件的,而 EventTarget 提供了添加、移除和触发事件监听器的机制。

const signalAbout = AbortSignal.timeout(10);signalAbout.addEventListener("abort", (e) => {    console.log("aborted: ", e);})​

e的打印如下:
在这里插入图片描述

3. 实现一个主动取消的promise

const ac = new AbortController();const { signal } = ac;​const cancelablePromise = ({signal}) =>     new Promise((resolve, reject) => {        // 情况1:直接主动取消        signal?.throwIfAborted(); // 也可以用reject​        // 情况2:正常处理业务逻辑​        setTimeout(() => {            Math.random() > 0.5 ? resolve('data') : reject('fetch error');        }, 1000);​        // 情况3:超时 todo?​        // 监听取消        signal.addEventListener("abort", () => {            reject(signal?.reason);        });    })// 发起网络请求cancelablePromise({signal}).then(res => console.log('res: ', res)).catch(err => console.log('err: ', err))// 情况1 // ac.abort('用户离开页面了') // err:  用户离开页面了​// 情况2 正常请求 err:  fetch error || res:  data

4. 如何使用signal取消事件监听?

当对一个元素添加了多个事件监听,不需要像removeEventListener一样,每个事件都需要取消一次,每次都要写明对应事件的事件句柄

使用signal 只需要取消一次信号,全部事件监听都被取消

const ac = new AbortController();const { signal } = ac;const eleA = document.querySelector('#a');const eleB = document.querySelector('#b');​function aEleHandler () {}; // 事件eleA.addEventListener('click', aEleHandler, {signal}); // 无论绑定多少个事件,都只需要一个signal​eleB.addEventListener('click', () => {    ac.abort(); // 只需要取消一次})

5. 请求多个接口进行数据组装的场景

当网速不好的时候,如何取消这种不断进行的网络请求?

const ac = new AbortController();const { signal } = ac;const fetchAndRenderAction = (signal) => {    requestData(signal); // 多个串行或者并行的接口    drawAndRender(signal); // 异步渲染}​try{    fetchAndRenderAction({signal})}catch{    // dosomething...}

6. 总结

对于用户主动离开页面,或者用户的网络很卡的时候(预期返回顺序是:接口1 => 接口2;但是接口1返回太慢,导致顺序混乱。)这就需要手动终止请求。构造函数AbortController的实例信号量signal(可以作为ref存储起来),signal作为fetch的参数,在每次请求的时候,可以手动调用abort方法,取消上一次的请求。

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
在这里插入图片描述


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/159141.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1