当前位置:网站首页>AbortController的使用
AbortController的使用
2022-06-26 15:26: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/
边栏推荐
- 【TcaplusDB知识库】TcaplusDB常规单据介绍
- 2022北京石景山区专精特新中小企业申报流程,补贴10-20万
- RestCloud ETL抽取動態庫錶數據實踐
- Applicable and inapplicable scenarios of mongodb series
- 整理了一批脚本标准的函数模块(2021版)
- 使用RestCloud ETL Shell组件实现定时调度DataX离线任务
- 打新债注册开户安全吗,有没有什么风险?
- About selenium common. exceptions. Webdriverexception: message: an unknown server side error solution (resolved)
- Deployment of kubernetes' controller
- 【微信小程序】事件绑定,你搞懂了吗?
猜你喜欢

Evaluate:huggingface评价指标模块入门详细介绍

【TcaplusDB知识库】TcaplusDB单据受理-事务执行介绍

Halcon C # sets the form font and adaptively displays pictures

数据库-完整性约束
![[wechat applet] event binding, do you understand?](/img/83/6242e972538d0423fd4155140bb521.png)
[wechat applet] event binding, do you understand?

【ceph】CephFS 内部实现(四):MDS是如何启动的?--未消化
![[tcapulusdb knowledge base] Introduction to tcapulusdb general documents](/img/7b/8c4f1549054ee8c0184495d9e8e378.png)
[tcapulusdb knowledge base] Introduction to tcapulusdb general documents

BLE抓包调试信息分析

Applet: uniapp solves vendor JS is too large
杜老师说网站更新图解
随机推荐
English语法_形容词/副词3级 - 原级句型
Summer camp is coming!!! Chongchongchong
Redis-集群
Optimizing for vectorization
Mr. Du said that the website was updated with illustrations
The tablestack function of the epidisplay package of R language makes a statistical summary table (descriptive statistics of groups, hypothesis test, etc.), does not set the by parameter to calculate
Cache page keepalive use in Vue
There are so many vulnerabilities in tcp/ip protocol?
人力资源导出数据 excel VBA
【TcaplusDB知识库】TcaplusDB单据受理-创建业务介绍
Is it safe to open a new bond registration account? Is there any risk?
[tcapulusdb knowledge base] tcapulusdb system user group introduction
Learning memory barrier
【ceph】mkdir|mksnap流程源码分析|锁状态切换实例
Restcloud ETL resolves shell script parameterization
Sikuli automatic testing technology based on pattern recognition
R language dplyr package summary_ The at function calculates the mean and median of multiple data columns (specified by vectors) in the dataframe data, and specifies na RM parameter configuration dele
About selenium common. exceptions. Webdriverexception: message: an unknown server side error solution (resolved)
使用卷积对数据进行平滑处理
Redis cluster messages