前端如何取消接口调用

news/2024/11/17 9:38:25/文章来源:https://www.cnblogs.com/smileZAZ/p/18294774

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

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 reason
ac.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 状态为 trueAbortSignal 实例。

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://www.hqwc.cn/news/741841.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

篮球比赛电子计分牌

在学习单片机课设“篮球比赛电子计分牌”的时候遇到了很多问题。在网上搜索到的资源很杂很乱,很多内容都需要付费,在学习的过程遇到了不少的阻力,因此我打算把我所做的拿出来与大家共同讨论,不足的地方还请多多指教哈。学艺不精,成绩仅为良好,大家参考就行。另外能激发后…

学习SpringCloud环境搭配

今天准备学习一下springcloud,在网上找了一个最新的学习视频需要更新一下之前安装的软件版本。突然想起来我还有个博客园的账号,就想记录一下环境搭建。 主要是分为以下几个部分Java 17+ Maven 3.9+ Mysql 8.0+ cloud 2023.0.0 boot 3.2.0 cloud alibaba 2022.0.0.0 之前…

进度报告4

(1)代码案例练习 1.public class helloworld { public static void main(String[] args) { double Price;int month;String x; Price=price(1000,6,"头等舱") ; System.out.println("优惠价为:"+Price); } public static double price(double a,int b,St…

day2

SSRF漏洞 1.SSRF漏洞介绍 SSRF(Server-Side Request Forgery)服务端请求为伪造,SSRF是⼀种由攻击者构造形成由服务端发起请求的⼀个安全漏洞。 ⼀般情况下,SSRF攻击的⽬标是从外⽹⽆法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连⽽与外⽹隔离…

[二、状态管理]2管理组件拥有的状态(4)@Provide装饰器和@Consume装饰器:与后代组件双向同步

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。 其中@Provide装饰的变量是在祖先节点中,可以理解为被“提供…

dedecms搭建网站怎么更换编辑器

入口: 系统 > 系统设置 > 系统基本参数 > 核心设置 > 编辑器默认可选参数: wangEditor 、 ckeditor 、 fck本文来自博客园,作者:黄文Rex,转载请注明原文链接:https://www.cnblogs.com/hwrex/p/18294690

DedeCMS网站安装成功后点击登录网站后台报404错误怎么办?

DedeCMS 默认的管理后台路径为 /dede 。遇到这个问题,需先检查 /dede 目录是否被重命名了。如果被重命名了,改回 /dede 即可。或直接在浏览器地址栏手动输入相应的管理后台路径,就可以打开后台登录页面了。本文来自博客园,作者:黄文Rex,转载请注明原文链接:https://www.…

关于DedeCMS版本号的说明

DedeCMS V5.7.73及后续的版本将采用 Semantic Versioning Specification (SemVer)(语义化版本 2.0.0) 进行维护。 语义化版本 2.0.0版本格式:主版本号.次版本号.修订号,版本号递增规则如下: 1、主版本号:当你做了不兼容的 API 修改, 2、次版本号:当你做了向下兼容的功能性…

zblog报错“Invalid argument supplied for foreach”或者“unserialize(): Error at offset”的解决办法

大部分的报错提示是:”Invalid argument supplied for foreach“也有提示”unserialize(): Error at offset“的,本文来分享下这个bug的原因和解决办法。 BUG原因: zblog1.7版本改造了system的config表,这个表里面存放的是程序的核心内容,例如域名、语言版本、网站名称等等…

PC触摸屏之设备维护【PackGo】

TIA Portal V16平台Pack&Go功能如何使用? TIA Portal V16平台Pack&Go功能如何使用 (siemens.com.cn)简介 当我们无法建立从组态PC到HMI设备的直接连接,例如,现场PC未安装TIA Portal软件,还需要将项目下载到HMI设备,除了使用U盘方式下载程序外,还可以创建P…

ZBlog网站固定域名出错不能登入

使用空间面板的文件管理或者 FTP 修改文件:path/zb_users/c_option.php; 如果是固定域名出错,需要关闭固定域名功能,请在 c_option.php增加项目: ZC_PERMANENT_DOMAIN_ENABLE => false, //1.7.3版本及以后版本使用//或是 ZC_PERMANENT_DOMAIN_WHOLE_DISABLE => true…

imagecreatefrompng(): gd-png: libpng warning: iCCP: known incorrect sRGB profile

问题描述: imagecreatefrompng(): gd-png: libpng warning: iCCP: known incorrect sRGB profile 解决方法: 更新 GD 库或 调整PHP版本宝塔的话, 可以安装依赖yum install libpng libpng-devel -y补充: 如果后台先安装的“一条大河应用盒子”,这个也启用一下, 不然也会报…