AbortSignal:以前我沒得選,現(xiàn)在我想中止Promise
大家好,我卡頌。
遙想數(shù)年前的一次面試,面試官問我:promise有什么缺點?
真是百思不得姐啊...
答案是:promise一旦初始化,就不能中止。這是由promise的實現(xiàn)決定的。
AbortSignal的出現(xiàn)使promise從語義上變?yōu)榭芍兄沟摹2⑶遥灰弦?guī)范,所有異步操作都能變?yōu)椤缚芍兄沟摹埂?/p>
AbortSignal是什么
AbortSignal是個實驗性API,不過兼容性還不錯,而且polyfill實現(xiàn)起來也不復(fù)雜。
AbortSignal可以實例化一個「信號對象」(signal object)。
AbortController可以實例化一個「信號對象」的控制器。
就像遙控器可以發(fā)出信號關(guān)電視一樣,AbortController的實例可以控制中止信號。
只要符合AbortSignal的接入規(guī)范,任何異步操作都能實現(xiàn)中止功能。
舉個例子,首先new一個控制器實例:
- // 控制器實例
- const controller = new AbortController();
- const signal = controller.signal;
其中signal是控制器對應(yīng)的「信號對象」。
「信號對象」可以監(jiān)聽abort事件,當(dāng)信號被中止時被觸發(fā)。
調(diào)用controller.abort()方法后會中止信號,此時signal.aborted為true。
- // 監(jiān)聽 abort 事件
- signal.addEventListener('abort', () => {
- console.log("信號中止!")
- });
- // 控制器中止信號
- controller.abort();
- console.log('是否中止:', signal.aborted);
如上代碼調(diào)用后會依次打印:
- 信號中止!
- 是否中止:true
在fetch中的應(yīng)用
fetch API已經(jīng)集成了AbortSignal。
只需要將controller內(nèi)的「信號對象」作為signal參數(shù)傳給fetch:
- const controller = new AbortController();
- fetch(url, {
- signal: controller.signal
- });
當(dāng)調(diào)用controller.abort()后,fetch的promise會變?yōu)锳bortError DOMException reject:
- fetch('xxxx', {
- signal: controller.signal
- }).then(() => {}, err => {
- if (err.name == 'AbortError') {
- // 中止信號
- } else {
- // 其他錯誤
- }
- })
可以在此時處理中止后的操作。
這里有個取消視頻下載Demo[1],可以看看fetch如何配合AbortSignal實現(xiàn)取消下載
與任何異步操作結(jié)合
不僅是fetch,任何異步操作只要符合如下規(guī)范,都可以與AbortError集成:
- 將AbortSignal(信號對象)作為API的signal參數(shù)傳入
- 約定如果API返回的promise變?yōu)锳bortError DOMException reject則代表操作被中止
- 如果signal.aborted === true則立刻讓promise變?yōu)閞eject
- 觀測AbortSignal狀態(tài)的變化
如果API應(yīng)用場景比較復(fù)雜(比如需要考慮多線程通信),文檔中提供了一套基于「訂閱發(fā)布」的abort-algorithms[2]機制來完成步驟4。
總結(jié)
雖然AbortSignal原理很簡單,但只要遵守接入規(guī)范,他的可擴展性是很強的。
比如,可以將一個signal傳給多個符合規(guī)范的API,就能用一個控制器中止多個API的調(diào)用。
就像一個遙控器,同時操作家里的空調(diào)、電視、洗衣機,你愛了么?
參考資料
[1]取消視頻下載Demo:
https://mdn.github.io/dom-examples/abort-api/[2]abort-algorithms:
https://dom.spec.whatwg.org/#abortsignal-abort-algorithms