当前位置:网站首页>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/
边栏推荐
- Handling methods for NVIDIA deepstream running delay, jamming and crash
- 为什么 Oracle 云客户必须在Oracle Cloud 季度更新发布后自行测试?
- Synchronized and lock escalation
- 做一篇人人能搞懂的ThreadLocal(源码)
- Leetcode 724. Find the central subscript of the array (yes, once)
- R language objects are stored in JSON
- Elegant custom ThreadPoolExecutor thread pool
- Calcul de la confidentialité Fate - Prévisions hors ligne
- AutoCAD - line width setting
- Strong, weak, soft and virtual references of ThreadLocal
猜你喜欢

volatile与JMM

ReentrantLock、ReentrantReadWriteLock、StampedLock

【业务安全-04】万能用户名及万能密码实验

隐私计算FATE-离线预测

ThreadLocal之强、弱、軟、虛引用

初识云原生安全:云时代的最佳保障

How QT sets some areas to be transparent in the background image

Interpretation of new version features of PostgreSQL 15 (including live Q & A and PPT data summary)

基于SSM的Web网页聊天室系统

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
随机推荐
为什么 Oracle 云客户必须在Oracle Cloud 季度更新发布后自行测试?
Pri3d: a representation learning method for 3D scene perception using inherent attributes of rgb-d data
Practice of constructing ten billion relationship knowledge map based on Nebula graph
Massive data! Second level analysis! Flink+doris build a real-time data warehouse scheme
PR second training notes
How QT sets some areas to be transparent in the background image
élégant pool de threadpoolexecutor personnalisé
Référence forte, faible, douce et virtuelle de threadlocal
线程同步之信号量
AutoCAD - line width setting
June 27, 2022 Daily: swin transformer, Vit authors and others said: a good basic model is the simple pursuit of CV researchers
Dynamic Networks and Conditional Computation论文简读和代码合集
Make a ThreadLocal (source code) that everyone can understand
Interview question: rendering 100000 data solutions
Gaode map IP positioning 2.0 backup
注解学习总结
How to select cross-border e-commerce multi merchant system
【PHP代码注入】PHP语言常见可注入函数以及PHP代码注入漏洞的利用实例
Notes learning summary
Acwing game 57