別人不會告訴你的JavaScript知識:Promise 鏈式調用的另一種使用方式

爲啥突然要記錄下這個Promise鏈式調用呢?我覺得有必要強調一下。

在網絡上大多數對Promise鏈式調用都是說下面這個代碼(代碼塊1)

new Promise((resolve,reject)=>{
    resolve({data:1})
}).then(res=>{
 return res;
})
.then(res=>{
 return res;
})
.then(res=>{
 return res;
})
//......省略100個then
.then(res=>{
 return res;
})
.then(res=>{
 return res;
})

這種then不斷接下去的一種形式,其實大多數情況下夠用了。


最近在學習axios的實現,遇到了一種很有意思的鏈式調用方式,場景如下:

  1. let arr=[請求攔截器,請求攔截器,發起請求,響應攔截器,響應攔截器]
  2. arr的元素格式如下:{resolve:()=>{},reject:()=>{}} ,這是所有數組元素的實現協議,並且函數必須返回Promise.reject或則Promise.resolve

目標:

  1. 按順序執行所有arr裏面的resolve函數,
  2. 如果中途遇到reject情況可以,在arr最後一個函數執行後catch錯誤信息
  3. 如果都通過情況,可以通過then獲取最終結果
  4. 支持異步和同步

 

實現代碼:

var arr = [];//函數鏈,
var result = 1;//被函數鏈操作的數據
for (let i = 0; i < 5; i++) {
    arr.push({
        resolve: () => {
            if (i % 2 == 0) {
                return new Promise((resolve, reject) => {
                    setTimeout(()=>{
                        result+=1;
                        resolve({data:result,respone:{code:0}});
                    },200)
                  //  reject({respone:{code:1}}) 如果是錯誤就觸發reject外賣可以獲取到
                })
            }
            else {
                result += 1;
                return { data: result }
            }
        },
        reject: () => {
            result += 1;
            return { data: result }
        }
    })
}

let promise = Promise.resolve({ data: "1" });
while (arr.length) {
    let { resolve, reject } = arr.shift();
    console.log(resolve, reject)
    /**
     * then方法的第一個參數是resolved狀態的回調函數,
     * 第二個參數(可選)是rejected狀態的回調函數。
     */

    /**
     * then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。
     * 因此可以採用鏈式寫法,即then方法後面再調用另一個then方法。
     */
    promise = promise.then(resolve, reject)  
}


promise.then((resolve, reject) => {
    console.log("resolve", resolve) // {data: 6,respone:{code:0}}
}).catch(e=>{
    console.log("err",e)
})


上面數組裏面的reject函數可以捕獲到上一個原生的錯誤信息,並返回給下一個元素,具體可以如下實現

 



var arr = [];//函數鏈,
var result = 1;//被函數鏈操作的數據
for (let i = 0; i < 5; i++) {
    arr.push({
        resolve: () => {
            if (i % 2 == 0) {
                return new Promise((resolve, reject) => {
                    // setTimeout(()=>{
                    //     result+=1;
                    //     resolve({data:result,respone:{code:0}});
                    // },200)
                    reject({respone:{code:1,index:i}}) //如果是錯誤就觸發reject外賣可以獲取到
                })
            }
            else {
                result += 1;
                return { data: result }
            }
        },
        reject: (e) => {
            console.log("上一個原生的錯誤",e)
            result += 1;
            //========重點看這裏
            //如果想下個元素不進入reject,可以返回resolve
            //但是這樣也會有弊端,不會觸發最後一個原生的catch,也無法處理異常
            return Promise.reject({ data: result,error:"reject的信息" })
        }
    })
}

let promise = Promise.resolve({ data: "1" });
while (arr.length) {
    let { resolve, reject } = arr.shift();
    console.log(resolve, reject)
    /**
     * then方法的第一個參數是resolved狀態的回調函數,
     * 第二個參數(可選)是rejected狀態的回調函數。
     */

    /**
     * then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。
     * 因此可以採用鏈式寫法,即then方法後面再調用另一個then方法。
     */
    promise = promise.then(resolve, reject)  
}


promise.then((resolve, reject) => {
    console.log("resolve", resolve) // {data: 6,respone:{code:0}}
}).catch(e=>{
    console.log("err",e)
})

 

深入解說:

  1. 本質上:這段代碼和代碼塊1的功能是一樣的,實際執行的程序和最終的效果依舊是then.then.then這種結果
  2. 區別是:在代碼層面解決了鏈式裏面所有函數的依賴,不需要把函數都寫在then裏面一層接一層的堆疊代碼
  3. 減少函數和promise.then的解耦

以下代碼扮演中介者的角色,把promise.then和對應的函數糅合到一塊,生成如代碼塊1那樣的程序,解除promise.then和對應函數的耦合,讓他們不需要相互認識,讓開發者專心寫對應的函數功能&&不需要關係執行過程和次序

while (arr.length) {
//...

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章