当前位置: 首页 > 科技观察

AbortSignal:之前没有选择,现在想中止Promise

时间:2023-03-13 18:22:11 科技观察

大家好,我是Kason。回想几年前的一次面试,面试官问我:promises有什么缺点?实在想不通。。。答案是:promise一旦初始化,就无法终止。这是由承诺的执行情况决定的。AbortSignal的出现使得承诺在语义上是可中止的。此外,只要符合规范,所有异步操作都可以“中止”。什么是中止信号?AbortSignal是一个实验性的API,但是兼容性还不错,polyfill的实现也不复杂。AbortSignal可以实例化一个“信号对象”。AbortController可以实例化一个“信号对象”控制器。就像遥控器可以发送信号来关闭电视一样,AbortController的实例可以控制中止信号。任何异步操作只要符合AbortSignal的接入规范,都可以实现abort功能。比如先new一个controller实例://controllerinstanceconstcontroller=newAbortController();constsignal=controller.signal;其中signal是控制器对应的“信号对象”。“信号对象”可以监听中止事件,并在信号中止时被触发。信号在调用controller.abort()方法后会中止,此时signal.aborted为true。//监听中止事件signal.addEventListener('abort',()=>{console.log("Signalabort!")});//控制器中止信号controller.abort();console.log('中止:',signal.aborted);以上代码调用后,会依次打印:Signalaborted!是否中止:truefetchAPI在fetch的应用中集成了AbortSignal。只需将控制器中的“信号对象”作为信号参数传递给获取:constcontroller=newAbortController();获取(网址,{信号:控制器。信号});调用controller.abort()后,fetch的promise会变成RejectforAbortErrorDOMException:fetch('xxxx',{signal:controller.signal}).then(()=>{},err=>{if(err.name=='AbortError'){//abort信号}else{//其他错误}})此时可以处理abort后的操作。这是一个取消视频下载的演示[1]。可以看到fetch是如何配合AbortSignal来实现取消下载和任意异步操作的组合。不仅仅是fetch,任何异步操作只要满足以下规范都可以与AbortError集成:作为API的signal参数,如果API返回的promise变为AbortErrorDOMExceptionreject,则表示操作中止。如果signal.aborted===true,promise将立即被拒绝。观察AbortSignal状态的变化。如果API应用场景比较复杂(比如需要考虑多线程通信),文档提供了一套基于“订阅发布”的abort-algorithms[2]机制来完成第4步。总结虽然原理AbortSignal的实现非常简单,只要遵循访问规范即可,扩展性很强。例如,你可以将一个信号传递给多个符合规范的API,你可以用一个控制器停止多个API的调用。像遥控器一样,可以同时操作家里的空调、电视、洗衣机。你喜欢吗?参考[1]取消视频下载Demo:https://mdn.github.io/dom-examples/abort-api/[2]abort-algorithms:https://dom.spec.whatwg.org/#abortsignal-abort-算法