大多数情况下,网络请求先请求,先响应。但是在某些情况下,由于一些未知的问题,可能会导致先请求的api稍后返回。最简单的解决办法就是加一个加载状态,所有请求都完成后才能进行下一次请求。但并非所有企业都能采用这种方法。这时候开发者就需要进行处理,避免渲染出错误的数据。使用“版本号”,我们可以通过版本号来决定业务处理和数据渲染:constinvariant=(condition:boolean,errorMsg:string)=>{if(condition){thrownewError(errorMsg)}}letversionForXXXQuery=0;constcheckVersionForXXXQuery=(currentVersion:number)=>{//如果版本不匹配,将抛出错误invariant(currentVersion!==versionForXXXQuery,'当前版本错误')}constXXXQuery=async()=>{//这里只能使用++versionForXXXQuery,不能使用versionForXXXQuery++//否则版本永远不会对应constqueryVersion=++versionForXXXQuery;//业务请求checkVersion(queryVersion)//业务处理//?界面渲染//业务请求checkVersion(queryVersion)//业务处理//?界面渲染}这样,第一个请求的api会因为错误而中止执行,但最终只会在界面上渲染最新版本的请求。但是这种方案对业务的侵入性太大。虽然我们可以使用类和AOP来简化代码和逻辑。但是对于开发还是不友好。这时候我们就可以使用AbortController。使用AbortControllerAbortController取消请求之前就不多说了,先用AbortController完成上面同样的功能。让abortControllerForXXXQuery:AbortController|null=nullconstXXXQuery=async()=>{//当前有一个abortcontroller,直接取消最后一个if(abortControllerForXXXQuery){abortControllerForXXXQuery.abort()}//创建一个新controllerabortControllerForXXXQuery=newAbortController();//获取信号const{signal}=abortControllerForXXXQueryconstresA=awaitfetch('xxxA',{signal});//业务处理//?界面渲染constresB=awaitfetch('xxxB',{signal});//业务处理//?界面渲染}我们可以看到代码很简单,同时增强了性能,浏览器会提前停止获取数据(注意:服务器还是会处理多个请求,服务器压力只能通过负载减少)。AbortController去除绑定事件虽然代码很简单,但是为什么需要添加一个AbortController类而不是直接添加一个api来中止网络请求操作呢?这不是增加了复杂度吗?作者起初也是这么想的。后来才知道。AbortController类更复杂,但它是通用的,因此AbortController可以被其他Web标准和JavaScript库使用。constcontroller=newAbortController()const{signal}=controller//添加事件并传递signalwindow.addEventListener('click',()=>{console.log('canabort')},{signal})window.addEventListener('click',()=>{console.log('click')});//开始请求并添加signalfetch('xxxA',{signal})//移除第一次点击事件并中止挂起的请求控制器。abort()是泛型AbortController既然是泛型,是不是也可以终止业务方法呢?答案是肯定的。我们先来看看AbortController为什么可以通用?AbortController提供了一个信号量信号和abort中止方法,通过它可以获取状态,获取绑定事件。constcontroller=newAbortController();//获取信号量const{signal}=controller;//获取当前是否执行过abort,当前返回falsesignal.aborted//添加事件signal.addEventListener('abort',()=>{console.log('triggerabort')})//添加事件signal.addEventListener('abort',()=>{console.log('triggerabort2')})//abort(不能解构直接执行abort,有this指向问题)//consoleprintingtriggersabort,triggersabort2controller.abort()//当前是否执行过abort,返回turesignal.aborted//consolenoresponsecontroller.abort();毫无疑问,上面的事件添加了abort事件的监听器。综上,作者简单的封装了AbortController。Helper类看起来像这样:execute调用方法,如果只需要信号状态,不需要在子类中实现*/abort=():void=>{}/***检查当前是否可以执行*@paramuseBoolean是否使用布尔值return*@returns*/checkCanExecution=(useBoolean:boolean=false):boolean=>{const{aborted}=this.signal//如果使用布尔值,返回是否可以继续执行if(useBoolean){return!aborted}//直接抛出异常if(aborted){thrownewError('abort已经触发');}returntrue}}这样开发者可以添加子类继承AbortControllerHelper,放到signal中。然后通过一个AbortController中止多个甚至多个不同的事件。鼓励如果您觉得这篇文章不错,希望您能给我一些鼓励,帮我在我的github博客下star。博客地址参考AbortControllerMDN
