爲啥突然要記錄下這個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的實現,遇到了一種很有意思的鏈式調用方式,場景如下:
- let arr=[請求攔截器,請求攔截器,發起請求,響應攔截器,響應攔截器]
- arr的元素格式如下:{resolve:()=>{},reject:()=>{}} ,這是所有數組元素的實現協議,並且函數必須返回Promise.reject或則Promise.resolve
目標:
- 按順序執行所有arr裏面的resolve函數,
- 如果中途遇到reject情況可以,在arr最後一個函數執行後catch錯誤信息
- 如果都通過情況,可以通過then獲取最終結果
- 支持異步和同步
實現代碼:
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的功能是一樣的,實際執行的程序和最終的效果依舊是then.then.then這種結果
- 區別是:在代碼層面解決了鏈式裏面所有函數的依賴,不需要把函數都寫在then裏面一層接一層的堆疊代碼
- 減少函數和promise.then的解耦
以下代碼扮演中介者的角色,把promise.then和對應的函數糅合到一塊,生成如代碼塊1那樣的程序,解除promise.then和對應函數的耦合,讓他們不需要相互認識,讓開發者專心寫對應的函數功能&&不需要關係執行過程和次序
while (arr.length) {
//...
}