大家好,我卡颂。

遐想数年前的一次面试,面试官问我:promise有什么毛病?

真是百思不得姐啊...

答案是:promise一旦初始化,就不能停止。这是由promise的实现决定的。

AbortSignal的呈现使promise从语义上变为可停止的。并且,只有符合规范,所有异步操作都能变为可停止的

AbortSignal是什么

AbortSignal是个实验性API,不过兼容性还不错,而且polyfill实现起来也不简单。

AbortSignal能够实例化一个信号对象signal object)。

AbortController能够实例化一个信号对象的控制器。

就像遥控器能够发出信号关电视一样,AbortController的实例能够管制停止信号。

只有合乎AbortSignal的接入标准,任何异步操作都能实现停止性能。

举个例子,首先new一个控制器实例:

// 控制器实例const controller = new AbortController();const signal = controller.signal;

其中signal是控制器对应的信号对象

信号对象能够监听abort事件,当信号被停止时被触发。

调用controller.abort()办法后会停止信号,此时signal.abortedtrue

// 监听 abort 事件signal.addEventListener('abort', () => {  console.log("信号停止!")});// 控制器停止信号controller.abort(); console.log('是否停止:', signal.aborted); 

如上代码调用后会顺次打印:

  1. 信号停止!
  2. 是否停止:true

在fetch中的利用

fetch API曾经集成了AbortSignal

只须要将controller内的信号对象作为signal参数传给fetch

const controller = new AbortController();fetch(url, {  signal: controller.signal});

当调用controller.abort()后,fetchpromise会变为AbortError DOMException reject

fetch('xxxx', {  signal: controller.signal}).then(() => {}, err => {  if (err.name == 'AbortError') {     // 停止信号  } else {    // 其余谬误  }})

能够在此时解决停止后的操作。

这里有个勾销视频下载Demo,能够看看fetch如何配合AbortSignal实现勾销下载

与任何异步操作联合

不仅是fetch,任何异步操作只有合乎如下标准,都能够与AbortError集成:

  1. AbortSignal(信号对象)作为APIsignal参数传入
  2. 约定如果API返回的promise变为AbortError DOMException reject则代表操作被停止
  3. 如果signal.aborted === true则立即让promise变为reject
  4. 观测AbortSignal状态的变动

如果API利用场景比较复杂(比方须要思考多线程通信),文档中提供了一套基于订阅公布的abort-algorithms机制来实现步骤4。

总结

尽管AbortSignal原理很简略,但只有恪守接入标准,他的可扩展性是很强的。

比方,能够将一个signal传给多个符合规范的API,就能用一个控制器停止多个API的调用。

就像一个遥控器,同时操作家里的空调、电视、洗衣机,你爱了么?

欢送退出人类高质量前端框架钻研群,带飞