大家好,我卡颂。
遐想数年前的一次面试,面试官问我: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.aborted
为true
。
// 监听 abort 事件
signal.addEventListener('abort', () => {console.log("信号停止!")
});
// 控制器停止信号
controller.abort();
console.log('是否停止:', signal.aborted);
如上代码调用后会顺次打印:
- 信号停止!
- 是否停止:true
在 fetch 中的利用
fetch API
曾经集成了AbortSignal
。
只须要将 controller
内的 信号对象 作为 signal
参数传给fetch
:
const controller = new AbortController();
fetch(url, {signal: controller.signal});
当调用 controller.abort()
后,fetch
的 promise
会变为AbortError DOMException reject
:
fetch('xxxx', {signal: controller.signal}).then(() => {}, err => {if (err.name == 'AbortError') {// 停止信号} else {// 其余谬误}
})
能够在此时解决停止后的操作。
这里有个勾销视频下载 Demo,能够看看
fetch
如何配合AbortSignal
实现勾销下载
与任何异步操作联合
不仅是 fetch
,任何异步操作只有合乎如下标准,都能够与AbortError
集成:
- 将
AbortSignal
(信号对象)作为API
的signal
参数传入 - 约定如果
API
返回的promise
变为AbortError DOMException reject
则代表操作被停止 - 如果
signal.aborted === true
则立即让promise
变为reject
- 观测
AbortSignal
状态的变动
如果 API
利用场景比较复杂(比方须要思考多线程通信),文档中提供了一套基于 订阅公布 的 abort-algorithms 机制来实现步骤 4。
总结
尽管 AbortSignal
原理很简略,但只有恪守接入标准,他的可扩展性是很强的。
比方,能够将一个 signal
传给多个符合规范的 API
,就能用一个控制器停止多个API
的调用。
就像一个遥控器,同时操作家里的空调、电视、洗衣机,你爱了么?
欢送退出人类高质量前端框架钻研群,带飞