优雅的终止Fecth和异步任务
自从有了Promise,我们编写异步任务就变的很简单的。避免了层层嵌套的回调函数。自身提供的统一接口更方便的管理、控制一步任务。
当然,Promise也有自己的不足、比如无法取消。
因此、有了AbortController。目前官方只有Fetch Api实现了该机制;其实我们自己可以通过该对象(AbortController
)实现优雅的取消异步任务
AbortController
[MDN]
AbortController
接口表示一个控制器对象,允许你根据需要中止一个或多个 Web请求
如何创建一个AbortController对象
let controller = new AbortController();
上文创建的AbortController
对象,提供一个属性(signal
)和一个方法(abort
)来控制异步任务
-
signal
属性,用于设置事件的监听器 -
abort
方法,用于取消任务,当执行abort()方法时,- controller.signal 会触发abort事件
- controller.signal.aborted 的值为
true
使用方法
var controller=new AbortController();//新建一个controller对象
controller.signal.addEventListener('abort',console.log); //监听controller.signal的abort事件
controller.abort(); //取消
console.log(controller.signal.aborted) //输出signal.aborted属性,由于执行了abort方法,这里变成了true
输出:
- Event {isTrusted: true, type: ‘abort’, target: AbortSignal, currentTarget: AbortSignal, eventPhase: 2, …}
- true
注意:
注意:
- 当
abort()
被调用时,fetch()
promise 拒绝一个名为AbortError
的DOMException
。
与Fetch一起使用
fetch,执行一个web请求
fetch返回的是一个promise,promise的缺点是无法取消的,所以我们借助AbortController对象来取消,
查看fetch文档、我们发现option配置有个signal
配置,这个就是fecth官方对于AbortController的支持,直接使用就行
伪代码:
var url="...";
var controller=new AbortController();
fetch(url,{
signal:controller.signal
})
//fetch 内部会对signal进行监听,如果遇到abort事件,fetch将终止请求
封装一个完整实例
//定义一个Http类,封装fetch操作
class Http{
constructor(){
this.ctrl=new AbortController();
}
query(url,options){
var controller=this.ctrl;
return fetch(url,Object.assign({ signal: controller.signal},options||{}))
}
abort(){
this.ctrl.abort();
}
}
//实例化Http对象
var http=new Http();
//调用方法
http.query('https://www.baidu.com').then(res=>{
console.log("success")
}).catch(err=>console.log);
setTimeout(function(){
//终止请求
http.abort();
},10)
//output:
//DOMException: The user aborted a request.
注意:
- AbortController是可以取消多个fetch任务的,也就是多个fetch任务都使用了同一个AbortController对象的signal属性
取消自定义异步任务
前面说到AbortController也可取消其他的异步任务,现在我们来看看吧,
其实就是利用AbortController对象的singal属性的abort事件来取消自定义异步任务
class AsyncTask{
constructor(){
this.ctrl=new AbortController();
this.time=3000
}
run(){
return new Promise((resolve,reject)=>{
//这里使用setTimeout来模拟异步任务
const timer=setTimeout(function(){
console.log('success')
resolve()
},this.time)
this.ctrl.signal.addEventListener('abort', error=>{
clearTimeout(timer)
reject(error)
});
})
}
abort(){
this.ctrl.abort();
}
}
var at=new AsyncTask();
at.run().catch(err=>{
console.log(err)
})
//异步任务在2s后取消
setTimeout(function(){
at.abort()
},2000)
总结
AbortController
利用singal
属性,abort方法就可以终止异步任务AbortController
对象执行abort
方法时、触发signal
属性abort
事件,signal.aborted
属性变成true
fetch
接口内部已经实现AbortController
机制,通过signal
属性配置AbortController
对象可以用于取消自定义异步任务