AbortSignal:以前我沒得選,現(xiàn)在我想中止promise
大家好,我卡頌。
遙想數年前的一次面試,面試官問我:promise有什么缺點?

真是百思不得姐啊...
答案是:promise一旦初始化,就不能中止。這是由promise的實現(xiàn)決定的。
AbortSignal的出現(xiàn)使promise從語義上變?yōu)榭芍兄沟?。并且,只要符合?guī)范,所有異步操作都能變?yōu)?span style="font-size: 15px;box-sizing: border-box;font-weight: bolder;">可中止的。
AbortSignal是什么
AbortSignal是個實驗性API,不過兼容性還不錯,而且polyfill實現(xiàn)起來也不復雜。

AbortSignal可以實例化一個信號對象(signal object)。
AbortController可以實例化一個信號對象的控制器。
就像遙控器可以發(fā)出信號關電視一樣,AbortController的實例可以控制中止信號。

只要符合AbortSignal的接入規(guī)范,任何異步操作都能實現(xiàn)中止功能。
舉個例子,首先new一個控制器實例:
// 控制器實例
const controller = new AbortController();
const signal = controller.signal;
其中signal是控制器對應的信號對象。
信號對象可以監(jiān)聽abort事件,當信號被中止時被觸發(fā)。
調用controller.abort()方法后會中止信號,此時signal.aborted為true。
// 監(jiān)聽 abort 事件
signal.addEventListener('abort', () => {
console.log("信號中止!")
});
// 控制器中止信號
controller.abort();
console.log('是否中止:', signal.aborted);
如上代碼調用后會依次打?。?/span>
信號中止! 是否中止:true

在fetch中的應用
fetch API已經集成了AbortSignal。controller內的信號對象作為signal參數傳給fetch:const controller = new AbortController();
fetch(url, {
signal: controller.signal
});
controller.abort()后,fetch的promise會變?yōu)?/span>AbortError DOMException reject:fetch('xxxx', {
signal: controller.signal
}).then(() => {}, err => {
if (err.name == 'AbortError') {
// 中止信號
} else {
// 其他錯誤
}
})
fetch如何配合AbortSignal實現(xiàn)取消下載與任何異步操作結合
fetch,任何異步操作只要符合如下規(guī)范,都可以與AbortError集成:將
AbortSignal(信號對象)作為API的signal參數傳入約定如果
API返回的promise變?yōu)?/span>AbortError DOMException reject則代表操作被中止如果
signal.aborted === true則立刻讓promise變?yōu)?/span>reject觀測
AbortSignal狀態(tài)的變化
API應用場景比較復雜(比如需要考慮多線程通信),文檔中提供了一套基于訂閱發(fā)布的abort-algorithms機制來完成步驟4。
總結
AbortSignal原理很簡單,但只要遵守接入規(guī)范,他的可擴展性是很強的。signal傳給多個符合規(guī)范的API,就能用一個控制器中止多個API的調用。
