一個正在執行中的promise怎樣被取消?
其實就像一個執行中的ajax要被取消一樣,ajax
有abort()
進行取消,而且fetch api
也有了相關的規范-【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);
})
});
}
怎樣實現實現promise的取消?
方案1 - 借助reject 方法
我們都知道一個promise
對象狀態的改變是通過resolve
和reject
來執行的。那是不是可以借助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();
上面的方法可以正常執行,但是不夠通用,可以將Promise構造函數內的邏輯提取出來,作為一個回調傳進去。
改造一下
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…在調用, let p = Promise.race([p1, p2, p3,…])的時候,返回的p也是一個promise。那么p什么時候會被resolve或者被reject呢?
看race我們知道它是競速或賽跑的意思,所以p1, p2, p3 … 最先一個被resolve或者被reject的結果就是p的resolve或者reject的結果。所以后續的promise的resolve和reject都不會再被執行了。
代碼很簡單,其實夠短小精悍。
//傳入一個正在執行的promise
function getPromiseWithAbort(p){
let obj = {};
//內部定一個新的promise,用來終止執行
let p1 = new Promise(function(resolve, reject){
obj.abort = reject;
});
obj.promise = Promise.race([p, p1]);
return obj;
}
調用
var promise = new Promise((resolve)=>{
setTimeout(()=>{
resolve('123')
},3000)
})
var obj = getPromiseWithAbort(promise)
obj.promise.then(res=>{console.log(res)})
//如果要取消
obj.abort('取消執行')
控制面板輸出
error 取消執行
借助race
方法明顯的更簡潔,更易用。
最后
其實取消promise
執行和取消請求是一樣的,並不是真的終止了代碼的執行,而是對結果不再處理。另外fetch api
雖然增加了新的標准實現,但仍然存在兼容問題,而且只能在瀏覽器中使用。那么非瀏覽器的環境中呢?比如RN?所以如果想要達到一種通用的方式,那么本文的取消promise
的方式應該是個不錯的方式。
目前知名的axios庫也有abort能力,回頭看下它的實現方式,也歡迎小伙伴們留言討論。
---end,希望對你有用。
————————————————
原文鏈接:https://blog.csdn.net/zz_jesse/article/details/113154610