当前位置:网站首页>AbortController的使用
AbortController的使用
2022-06-27 14:23:00 【flytam】
今天介绍一个有用的 JavaScript api AbortController
AbortController是什么
AbortController 接口表示一个控制器对象,允许你根据需要中止一个或多个 Web 请求。你可以使用 AbortController.AbortController() 构造函数创建一个新的 AbortController。使用 AbortSignal 对象可以完成与 DOM 请求的通信
这个 api 简单来说就是可以提供一个能力给我们去提前终止一个 fetch 请求
一个终止 fetch 请求的 demo 如下:
fetchButton.onclick = async () => {
const controller = new AbortController();
// 点击abort button实现终止fetch请求
abortButton.onclick = () => controller.abort();
try {
const r = await fetch('/json', { signal: controller.signal });
const json = await r.json();
} catch (e) {
// 如果fetch请求被终止会抛出一个AbortError的错误
const isUserAbort = (e.name === 'AbortError');
}
};提前终止后这个请求在 network 面板中的 status 显示为 canceled
在没有AbortController这个 api 之前,我们是没法去让浏览器提前去终止一个请求的。而有了这个 api 之后,浏览器就能提前终止请求进而节约一些用户带宽。除此之外,这个 api 也能给我们带来一些新的开发模式
Controller 和 Signal
下面实例化了一个AbortController,它的signal属性就是一个AbortSignal
const controller = new AbortController();
const { signal } = controller;- controller 可通过
controller.abort()去终止它对应的signal signal本身是不能被直接终止的。可以将它传递给一些函数调用如 fetch 或者直接监听signal的状态变化(可以通过signal.aborted查看signal的状态或者监听它的abort事件)
实际使用
普通对象中的终止
一些旧的 DOM api 是不支持AbortSignal。例如WebScocket只提供了一个close方法当我们无需使用时进行关闭。如果要使用AbortSignal则可以类似以下的封装
function abortableSocket(url, signal) {
const w = new WebSocket(url);
if (signal.aborted) {
w.close(); // signal已经终中止的情况下马上关闭websocket
}
signal.addEventListener('abort', () => w.close());
return w;
}这个使用也很简单,但是需要注意的是如果signal已经终止的情况下是不会触发abort事件,需要我们先进行一个判断是否signal已经终止
移除事件监听
我们经常需要在 js 中处理 dom 的监听和卸载工作。但是下面的例子由于事件监听和卸载传入的函数不是同一个引用时不会生效的
window.addEventListener('resize', () => doSomething());
// 不会生效
window.removeEventListener('resize', () => doSomething());因此我们经常需要一些额外的代码去维护这个回调函数的引用的一致性。而有了AbortSignal之后我们就可以有一种的新的方式去实现
const controller = new AbortController();
const { signal } = controller;
window.addEventListener('resize', () => doSomething(), { signal });
controller.abort();因为addEventListener也能接收signal属性的。我们最后只需要调用controller.abort(),这个controller的signal传递的相关事件监听都会被自动相应卸载了
构造器模式
在 JavaScript 中我们可能需要在对象中管理非常复杂的生命周期,如WebSocket。我们需要执行开启然后执行一系列逻辑后终止。可能我们会写以下代码
const someObject = new SomeObject();
someObject.start();
// 执行一些操作后
someObject.stop();也可以通过AbortSignal进行实现
const controller = new AbortController();
const { signal } = controller;
const someObject = new someObject(signal);
// 执行一些操作后
controller.abort();- 这能非常清晰地表示这个对象只能被执行一次,只能从开始到结束,而不能反过来。如果它终止了后想再次使用则需要再次创建一个对象
- 可以在很多地方共享一个
signal。我们无需持有多个SomeObject的实例。只需要调用controller.abort(),这些SomeObject的实例都能被终止掉 - 如果
SomeObject内部也有调用像fetch之类的内部 api 只需要把这个signal继续传递,则fetch也能被一起终止掉
如下是一个例子。展示了两种 signal 的用法。传递给内置 apifetch和检查signal状态执行一些操作
export class SomeObject {
constructor(signal) {
this.signal = signal;
// 执行一些操作例如发请求
const p = fetch('/json', { signal });
}
doComplexOperation() {
if (this.signal.aborted) {
throw new Error(`thing stopped`);
}
for (let i = 0; i < 1_000_000; ++i) {
// 执行复杂操作
}
}
}react hook 中的异步调用
我们通常会在useEffect中进行一些异步 api 调用。借助signal可以在下一次useEffect重新调用 api 的时候将前一次的调用终止
function FooComponent({ something }) {
useEffect(() => {
const controller = new AbortController();
const { signal } = controller;
const p = (async () => {
const j = await fetch(url + something, { signal });
})();
return () => controller.abort();
}, [something]);
return <>...<>;
}也可以封装一个useEffectAsync的 hook
function useEffectAsync(cb,dependence) {
const controller = new AbortController();
const { signal } = controller;
useEffect(() => {
cb(signal);
return () => controller.abort();
},dependence)
}一些有用的 AbortSignal 方法
这些方法当前有可能还没有实现
AbortSignal.timeout(ms): 创建一个给定时间后终止的AbortSignal
function abortTimeout(ms) {
const controller = new AbortController();
setTimeout(() => controller.abort(), ms);
return controller.signal;
}AbortSignal.any(signals):创建一个AbortSignal,如果传入的任一signal终止了,这个返回的signal也会被终止
function abortAny(signals) {
const controller = new AbortController();
signals.forEach((signal) => {
if (signal.aborted) {
controller.abort();
} else {
signal.addEventListener('abort', () => controller.abort());
}
});
return controller.signal;
}AbortSignal.throwIfAborted():如果signal本身已经终止了,调用该方法会抛出执行abort(reason)时指定的 reason 异常;否则只会静默执行
if (signal.aborted) {
throw new Error(...);
}
// becomes
signal.throwIfAborted();这个方法目前不太容易 polyfill,但是可通过下面的工具函数实现
function throwIfSignalAborted(signal) {
if (signal.aborted) {
throw new Error(...);
}
}参考
https://whistlr.info/2022/abortcontroller-is-your-friend/
边栏推荐
- Great God developed the new H5 version of arXiv, saying goodbye to formula typography errors in one step, and the mobile phone can easily read literature
- Make a ThreadLocal (source code) that everyone can understand
- ThreadLocal之强、弱、软、虚引用
- Too many requests at once, and the database is in danger
- Design and implementation of food recipe and ingredients website based on vue+node+mysql
- 剑指 Offer II 039. 直方图最大矩形面积 单调栈
- 力扣 第 81 场双周赛
- R language objects are stored in JSON
- 【微服务|Sentinel】热点规则|授权规则|集群流控|机器列表
- 每日3题(1):找到最近的有相同 X 或 Y 坐标的点
猜你喜欢

ThreadLocal之强、弱、软、虚引用
![[business security-04] universal user name and universal password experiment](/img/09/73d8356d00cefb6d1af086669f69ff.png)
[business security-04] universal user name and universal password experiment

Integration of entry-level SSM framework based on XML configuration file
![[business security 03] password retrieval business security and interface parameter account modification examples (based on the metinfov4.0 platform)](/img/29/73c381f14a09ecaf36a98d67d76720.png)
[business security 03] password retrieval business security and interface parameter account modification examples (based on the metinfov4.0 platform)

Kyndryl partnered with Oracle and Veritas
![[OS command injection] common OS command execution functions and OS command injection utilization examples and range experiments - based on DVWA range](/img/f2/458770fc74971bef23f96f87733ee5.png)
[OS command injection] common OS command execution functions and OS command injection utilization examples and range experiments - based on DVWA range

Great God developed the new H5 version of arXiv, saying goodbye to formula typography errors in one step, and the mobile phone can easily read literature

CV领域一代宗师黄煦涛教授86岁冥诞,UIUC专设博士奖学金激励新锐

海量数据!秒级分析!Flink+Doris构建实时数仓方案

ReentrantLock、ReentrantReadWriteLock、StampedLock
随机推荐
[business security 03] password retrieval business security and interface parameter account modification examples (based on the metinfov4.0 platform)
Tsinghua & Shangtang & Shanghai AI & CUHK proposed Siamese image modeling, which has both linear probing and intensive prediction performance
Leetcode 724. 寻找数组的中心下标(可以,一次过)
American chips are hit hard again, and another chip enterprise after Intel will be overtaken by Chinese chips
Redis CacheClient
June 27, 2022 Daily: swin transformer, Vit authors and others said: a good basic model is the simple pursuit of CV researchers
Array related knowledge
数学建模经验分享:国赛美赛对比/选题参考/常用技巧
Sword finger offer II 039 Histogram maximum rectangular area monotonic stack
volatile与JMM
【业务安全03】密码找回业务安全以及接口参数账号修改实例(基于metinfov4.0平台)
What are the operating modes of the live app? What mode should we choose?
Design and implementation of reading app based on Web Platform
Notes learning summary
Unity3d best practices: folder structure and source control
Is there any discount for opening an account now? Is it safe to open an account online?
[daily 3 questions (3)] maximum number of balls in the box
Gaode map IP positioning 2.0 backup
Brief reading of dynamic networks and conditional computing papers and code collection
Handling methods for NVIDIA deepstream running delay, jamming and crash