乐趣区

关于前端:AbortSignal以前我没得选现在我想中止promise

大家好,我卡颂。

遐想数年前的一次面试,面试官问我: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 的调用。

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

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

退出移动版