如何更好的取消一個promise?
一個正在執(zhí)行中的promise怎樣被取消?
其實就像一個執(zhí)行中的ajax要被取消一樣,ajax有abort()進行取消,而且fetch api 也有了相關(guān)的規(guī)范-【AbortController】。
fetch 怎樣取消?
先來看下如何取消一個fetch請求
const?url?=?"https://bigerfe.com/api/xxxx"
let?controller;
let?signal;
function?requestA(){
?if?(controller?!==?undefined)?{
????????controller.abort();?//終止請求
????}
????if?("AbortController"?in?window)?{
????????controller?=?new?AbortController;
????????signal?=?controller.signal;
????}
????fetch(url,?{signal})
????????.then((response)?=>?{
????????????//do?xxx
????????????updateAutocomplete()
????????})
????????.catch((error)?=>?{
????????????//do?xxx
????????????handleError(error);
????????})
????});
}
怎樣實現(xiàn)實現(xiàn)promise的取消?
方案1 - 借助reject 方法
我們都知道一個promise對象狀態(tài)的改變是通過resolve和reject來執(zhí)行的。那是不是可以借助reject方法來模擬呢?
上代碼
//返回一個promise和abort方法
function?getPromise()?{
??let?_res,?_rej;
??
??const?promise?=?new?Promise((resolve,?reject)?=>?{
????_res?=?resolve;
????_rej?=?reject;
????setTimeout(()?=>?{
??????resolve('123')
????},?5000);
??});
??return?{
????promise,
????abort:?()?=>?{
??????_rej({
????????name:?"abort",
????????message:?"the?promise?is?aborted",
????????aborted:?true,
??????});
????}
??};
}
const?{?promise,?abort?}?=?getPromise();
promise.then(console.log).catch(e?=>?{
??console.log(e);
});
abort();
上面的方法可以正常執(zhí)行,但是不夠通用,可以將Promise構(gòu)造函數(shù)內(nèi)的邏輯提取出來,作為一個回調(diào)傳進去。
改造一下
function?getPromise(cb)?{
??let?_res,?_rej;
??
??const?promise?=?new?Promise((res,?rej)?=>?{
????_res?=?res;
????_rej?=?rej;
????cb?&&?cb(res,rej);
??});
??return?{
????promise,
????abort:?()?=>?{
??????_rej({
????????name:?"abort",
????????message:?"the?promise?is?aborted",
????????aborted:?true,
??????});
????}
??};
}
//主邏輯提取出來
function?runCb(resolve,reject){
????setTimeout(()=>{
????????resolve('1111')
????},3000)
}
const?{?promise,?abort?}?=?getPromise(runCb);
promise.then(console.log).catch(e?=>?{
??console.log(e);
});
方案2 ?- 借助 Promise.race() 方法
相信大家都知道race方法的作用,這里還是簡單介紹下。
當有若干個promise, p1, p2, p3…在調(diào)用, let p = Promise.race([p1, p2, p3,…])的時候,返回的p也是一個promise。那么p什么時候會被resolve或者被reject呢?
看race我們知道它是競速或賽跑的意思,所以p1, p2, p3 … 最先一個被resolve或者被reject的結(jié)果就是p的resolve或者reject的結(jié)果。所以后續(xù)的promise的resolve和reject都不會再被執(zhí)行了。
代碼很簡單,其實夠短小精悍。
//傳入一個正在執(zhí)行的promise
function?getPromiseWithAbort(p){
????let?obj?=?{};
????//內(nèi)部定一個新的promise,用來終止執(zhí)行
????let?p1?=?new?Promise(function(resolve,?reject){
????????obj.abort?=?reject;
????});
????obj.promise?=?Promise.race([p,?p1]);
????return?obj;
}
調(diào)用
var?promise??=?new?Promise((resolve)=>{
?setTimeout(()=>{
??resolve('123')
?},3000)
})
var?obj?=?getPromiseWithAbort(promise)
obj.promise.then(res=>{console.log(res)})
//如果要取消
obj.abort('取消執(zhí)行')

借助race方法明顯的更簡潔,更易用。
最后
其實取消promise執(zhí)行和取消請求是一樣的,并不是真的終止了代碼的執(zhí)行,而是對結(jié)果不再處理。另外fetch api雖然增加了新的標準實現(xiàn),但仍然存在兼容問題,而且只能在瀏覽器中使用。那么非瀏覽器的環(huán)境中呢?比如RN?所以如果想要達到一種通用的方式,那么本文的取消promise的方式應該是個不錯的方式。
目前知名的axios庫也有abort能力,回頭看下它的實現(xiàn)方式,也歡迎小伙伴們留言討論。
---end,希望對你有用。
點個『在看』支持下?
