1. 程式人生 > >JavaScript 中斷Promise鏈方法

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