Node.jsv15.0.0提供了一个全局实用程序APIAbortController,用于在选定的基于Promise的API中发出取消信号。在所有模块中可用,无需导入,此API的实现基于浏览器中的WebAPIAbortController。简单示例通俗地说,AbortController代表一个控制器对象,它允许我们根据需要中止一个或多个Web请求。下面是一个例子,ac.abort()方法会在1秒后执行,会触发abort事件,并且只会触发一次,可以通过abortSignal.aborted属性查看和更改。ac.signal.addEventListener('abort',()=>{console.log('Aborted!');console.log('ac.signal.aborted:',ac.signal.aborted);},{一次:true});setTimeout(()=>ac.abort(),1000)console.log('ac.signal.aborted:',ac.signal.aborted);中止请求在Node.js中,我们可以选择使用node-fetch这个请求处理库传递信号给fetch。假设请求需要等待5秒,大约2秒后执行abort()将中止请求。constac=newAbortController();importfetchfrom'node-fetch';consttimer=setTimeout(()=>ac.abort(),2000)try{const{statusText}=awaitfetch('http://localhost:3000/api',{signal:ac.signal})console.log(statusText);}catch(err){console.log(err.name);//AbortError}finally{clearTimeout(timer);}abortPromisedeliveryac.signalabortone正在运行的Promise要求我们为ac.signal注册一个abort事件并做一些处理。然后在任何地方调用ac.abort()来中止Promise。任何使用Promises表示中止操作的Web平台API都必须遵守以下原则:通过信号字典成员接受AbortSignal对象。表示通过拒绝具有“AbortError”类DOMException的Promise来中止操作。检查AbortSignal对象的aborted标志是否已经设置,如果是则立即拒绝,否则:使用中止算法机制以不与其他观察者发生冲突的方式观察AbortSignal对象的变化。以下异步Promise函数doSomeThingAsync的实现基本上遵循这些规则。classAbortErrorextendsError{constructor(message){super(message);this.name='AbortError';}}functiondoSomethingAsync({ac}){returnnewPromise((resolve,reject)=>{console.log('taskstart...');if(ac.aborted){returnreject(newAbortError('taskhandlerfailed','AbortError'));}consttimer=setTimeout(()=>{console.log('taskend...');resolve(1);},5000);ac.signal.addEventListener('abort',()=>{clearTimeout(timer);reject(newAbortError('taskhandlerfailed','AbortError'));},{once:true});});}setTimeout(()=>ac.abort(),2000)try{awaitdoSomethingAsync({ac});}catch(err){console.error(err.name,err.message);//AbortErrortaskhandlerfailed}注意:在Node.js中目前没有DOMException类,我们做不到这个newDOMException('taskhandlerfailed','AbortError')所以一开始我创建了一个AbortError类来模拟。Node.js中已经有一些支持传递信号的异步API,但是其DOMException错误也是通过封装在内部实现的://https://github.com/nodejs/node/blob/f6b1df2226/lib/internal/fs/promises.js#L98constlazyDOMException=hideStackFrames((message,name)=>{if(DOMException===undefined)DOMException=internalBinding('messaging').DOMException;returnnewDOMException(message,name);});//例如writeFileHandle//https://github.com/nodejs/node/blob/f6b1df2226/lib/internal/fs/promises.js#L282if(signal?.aborted){throwlazyDOMException('Theoperationwasaborted','AbortError');}参考https://dom.spec.whatwg.org/#abortcontroller-api-integrationhttps://nodejs.org/docs/latest-v15.x/api/globals.htm
