JavaScript 中斷Promise鏈方法
文章目錄
1 Promise
Promise,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件,在ES6得到支援。
且具有以下特點:
物件的狀態不受外界影響。Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。
一個簡單例子Promise 的例子。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 非同步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
2 Promise鏈及如何終止
2.1 現象
主要問題是:鏈式呼叫時,想在下層返回resolve的情況下,需要在中途得到某種resolve結果就終止呼叫鏈。(PS:下層可能是呼叫其他人編寫模組,比如引數不對,它仍會返回resolve,出現錯誤才會reject,本身下層Promise 返回reject是可以打斷呼叫鏈的)
下面有個鏈式呼叫Promise的測試函式
const promiseFun = function(param1){
return new Promise((resolve, reject)=>{
resolve(param1);
});
}
const promiseTest = function(param1, param2){
return new Promise((resolve, reject)=>{
promiseFun(1).then((number)=>{
console. info(`fun1 result:${number}`);
return promiseFun(2);
}).then((number)=>{
console.info(`fun2 result:${number}`);
return promiseFun(3);
}).then((number)=>{
console.info(`fun3 result:${number}`);
return promiseFun(4);
}).then((number)=>{
console.info(`fun4 result:${number}`);
}).catch((err)=>{
console.info(`promiseTest error:${err}`);
});
});
}
promiseTest('1','2').then((number)=>{
console.info(`promiseTest:${number}`);
}).catch((err)=>{
console.info(`promiseTest failed:${err}`);
});
現在遇到的一個問題是,比如我們在fun2時,我們呼叫reject 想終止該鏈式呼叫,但實際的結果是仍然會跑到console.info(fun3 result:${number}
)及console.info(fun4 result:${number}
)。
即:
promiseFun(1).then((number)=>{
console.info(`fun1 result:${number}`);
return promiseFun(2);
}).then((number)=>{
console.info(`fun2 result:${number}`);
if(number === 2){
reject(number)
}
else{
return promiseFun(3);
}
}).then((number)=>{
console.info(`fun3 result:${number}`);
return promiseFun(4);
}).then((number)=>{
console.info(`fun4 result:${number}`);
}).catch((err)=>{
console.info(`promiseTest error:${err}`);
});
2.2 原因
Promise的then方法接收兩個引數:
Promise.prototype.then(onFulfilled, onRejected)
若onFulfilled或onRejected是一個函式,當函式返回一個新Promise物件時,原Promise物件的狀態將跟新物件保持一致。
來自:https://promisesaplus.com/
解釋下原因:
1 我們編寫then函式一般情況下只寫了onFulfilled,也就是resolve結果的處理函式,而onRejected處理一般情況下都是沒有編寫的,所以鏈式呼叫丟擲的reject,因為鏈式呼叫上均沒有捕獲到,根據 原Promise物件的狀態將跟新物件保持一致的原理就會一路傳遞到catch中進行處理。
2 為什麼我們鏈式呼叫中reject沒有作用,因為reject僅僅改變的是外層包的promiseTest 返回Promise狀態。而在第二個鏈式呼叫then,沒做處理,所以第三個鏈式繼承了第一個鏈式呼叫返回的Promise 的resolve狀態,導致鏈式呼叫繼續向下執行。
2.3 解決方案
而針對上面的問題,我們想要在resolve的情況下,中斷或終止鏈式呼叫。
還是基於Promise的特點:原Promise物件的狀態將跟新物件保持一致。
我們僅需要在鏈式呼叫中,返回一個pending 狀態或reject狀態的Promise物件即可。後面then 所有resolve(onFulfilled)的處理函式就都不會跑到了。即:
return (new Promise((resolve, reject)=>{}));//返回pending狀態
return (new Promise((resolve, reject)=>{rejcet()}));//返回reject狀態 會被最後catch捕獲。
在測試程式碼中就想這樣
then((number)=>{
console.info(`fun2 result:${number}`);
if(number === 2){、
return (new Promise((resolve, reject)=>{}));
reject(number)
}
else{
return promiseFun(3);
}
3 參考連結
https://blog.csdn.net/ambit_tsai/article/details/80635594
http://es6.ruanyifeng.com/#docs/promise