當前位置:編程學習大全網 - 編程語言 - 實現promise.all方法

實現promise.all方法

1- Promise.all 的用法

逆向的去實現功能,最關鍵的前提是準確了解API,輸入、輸出、和註意事項。

這裏直接引用MDN:

Promise.all(iterable)?方法返回壹個 Promise 實例,此實例在 iterable 參數內所有的 promise 都“完成(resolved)”或參數中不包含 promise 時回調完成(resolve);如果參數中 promise 有壹個失敗(rejected),此實例回調失敗(reject),失敗的原因是第壹個失敗 promise 的結果。

MDN後面也給出了詳細說明:

此方法在集合多個promise的返回結果時很有用。

完成(Fulfillment):

如果傳入的可叠代對象為空,Promise.all會同步地返回壹個已完成(resolved)狀態的promise。

如果所有傳入的promise都變為完成狀態,或者傳入的可叠代對象內沒有promise,Promise.all返回的promise異步地變為完成。

在任何情況下,Promise.all返回的promise的完成狀態的結果都是壹個數組,它包含所有的傳入叠代參數對象的值(也包括非promise值)。

失敗/拒絕(Rejection):

如果傳入的promise中有壹個失敗(rejected),Promise.all異步地將失敗的那個結果給失敗狀態的回調函數,而不管其它promise是否完成。

個人感覺MDN解釋的比較清楚了,還是雲裏霧裏的話,可以反復細品壹下上面的說明。或者結合下面的代碼去理解。

2 - 手動實現Promise.all

面試美團的時候,面試官看我寫不出來,就說“既然妳知道了輸入和輸出是什麽,應該能寫出來了....”。

面試官其實不是在鄙視我“我不行”,而是在試圖引導我的思路,只是當時自己編程思路太差,最後還是沒寫出來。

但是面試官的提示,確實是壹個很好的思考思路。 先不管完整的Promise.all代碼是什麽樣子,甚至包括優化啥的。先想想"Promise.all(iterable)?方法返回壹個 Promise實例",就這麽簡單的壹句話怎麽寫呢?

function myPromiseAll(arr) { ?// 參數是壹個iterable對象,壹般是數組

// 返回壹個Promise實例

return new Promise((resolve, reject) => {

resolve("面試官讓我寫壹個Promise.all");

// 或者

// reject("我太笨了,寫不出來");

});

}

let pResult = myPromiseAll([]); ?// 先不要去想數組有沒有元素

pResult.then(value=>{

console.log(value); ?// 輸出: 面試官讓我寫壹個Promise.all

}, err=>{

console.log(err);

})

好了,如過看懂了,那麽最重要的壹步就完成了。是不是很簡單。

接下來,只要根據MDN的說明,壹步步完善內部函數的功能就行了。

我們先從“完成”情況下手:

完成(Fulfillment):

A. 如果傳入的可叠代對象為空,Promise.all會同步地返回壹個已完成(resolved)狀態的promise。

B. 如果所有傳入的promise都變為完成狀態,或者傳入的可叠代對象內沒有promise,Promise.all返回的promise異步地變為完成。

C. 在任何情況下,Promise.all返回的promise的完成狀態的結果都是壹個數組,它包含所有的傳入叠代參數對象的值(也包括非promise值)。

請先看C,在完成情況下,會始終返回壹個數組.

function myPromiseAll(arr) {

// 定義壹個數組

let result = [];

return new Promise((resolve, reject) => {

// 現在只考慮 “在完成情況下” ,會返回壹個數組

resolve(result);

?

});

}

let pResult = myPromiseAll([]);

pResult.then(value=>{

console.log(pResult); ?// 輸出 Promise { <state>: "fulfilled", <value>: [] }

console.log(value); // 輸出:[]

})

那麽下面來實現B,B裏有分兩種情況:

元素是Promise實例

元素不是Promise實例

那先考慮元素不是Promise實例,從簡單的開始

function myPromiseAll(arr) {

let result = [];

return new Promise((resolve, reject) => {

for(let i = 0; i < arr.length; i++) {

result.push(arr[i]);

}

resolve(result);

?

});

}

let pResult = myPromiseAll([1,2,3]); ?// 元素不是Promise實例

pResult.then(value=>{

console.log(pResult); // 輸出: ?Promise { <state>: "fulfilled", <value>: (3) […] }

console.log(value); // 輸出: Array(3) [ 1, 2, 3 ]

})

最難的來了,元素都是Promise實例呢?

別慌,先寫頂層設計,再想細節(自上向下編程)

function myPromiseAll(arr) {

let result = [];

return new Promise((resolve, reject) => {

for(let i = 0; i < arr.length; i++) {

if(/*如果是Promise實例*/) {

} else {

result.push(arr[i]);

}

}

// 先想想,resolve放在這裏,對不對?

resolve(result);

?

});

}

繼續完善

function myPromiseAll(arr) {

let result = [];

return new Promise((resolve, reject) => {

// 數組為空,直接resolve了

if(arr.length == 0) {

resolve(result);

}

for(let i = 0; i < arr.length; i++) {

if(arr[i].then) { // 若元素是Promise實例,則會有then函數,這裏只是簡單的作為判斷標準

// 元素是Promise

arr[i].then(value => {

console.log(value);

result.push(value);

// 想壹想什麽時候resolve呢?--- 所有Promise實例都完成了

if(result.length == arr.length) {

? console.log("所有都完成了")

resolve(result);

}

})

} else {

result.push(arr[i]);

// 這段代碼跟上面重復,想想,能不能提取放到外面,會出現什麽情況呢?

if(result.length == arr.length) {

resolve(result);

}

}

}

});

}

let p1 = new Promise((resolve, reject)=> {

setTimeout(resolve, 2000, "P1 resolved");

})

let p2 = new Promise((resolve, reject)=> {

setTimeout(resolve, 3000, "P2 resolved");

})

let p3 = new Promise((resolve, reject)=> {

setTimeout(resolve, 4000, "P3 resolved");

})

let pResult = myPromiseAll([p1,p2,p3]);

pResult.then(value=>{

console.log(pResult);

console.log(value);

})

// 輸出

// P1 resolved

// P2 resolved

// P3 resolved

// 所有都完成了

// Promise { <state>: "fulfilled", <value>: (3) […] }

// Array(3) [ "P1 resolved", "P2 resolved", "P3 resolved" ]

完成情況寫完了,還剩失敗情況:

如果傳入的 promise 中有壹個失敗(rejected),Promise.all 異步地將失敗的那個結果給失敗狀態的回調函數,而不管其它 promise 是否完成。

function myPromiseAll(arr) {

let result = [];

return new Promise((resolve, reject) => {

// 如果數組為空,直接返回空數組

if(arr.length == 0) {

resolve(result);

}

for(let i = 0; i < arr.length; i++) {

if(arr[i].then) { // 若元素是Promise實例,則會有then函數,這裏只是簡單的作為判斷標準

// 元素是Promise

arr[i].then(value => {

console.log(value);

result.push(value);

// 想壹想什麽時候resolve呢?

if(result.length == arr.length) {

console.log("所有都成功了")

resolve(result);

}

}, err => {

console.log("很不幸,其中壹個失敗了");

// 註意到沒, 這裏沒有像上面的判斷 result.length == arr.length, 為什麽?

// 只要碰到 resolve 或 reject ,就結束了

reject(err);

})

} else {

result.push(arr[i]);

// 這段代碼跟上面重復,想想,能不能提取放到外面,會出現什麽情況呢?

if(result.length == arr.length) {

resolve(result);

}

}

}

});

}

let p1 = new Promise((resolve, reject)=> {

setTimeout(reject, 2000, "P1 rejected");

})

let p2 = new Promise((resolve, reject)=> {

setTimeout(resolve, 3000, "P2 resolved");

})

let p3 = new Promise((resolve, reject)=> {

setTimeout(resolve, 4000, "P3 resolved");

})

let pResult = myPromiseAll([p1,p2,p3]);

pResult.then(value=>{

console.log(pResult); ?// 是輸出成功

console.log(value);

}, err => {

console.log(pResult); ? // 還是輸出失敗呢?

console.log(err);

})

// 輸出

// 很不幸,其中壹個失敗了

// Promise { <state>: "rejected" }

// P1 rejected

// P2 resolved

// P3 resolved

為什麽最後還是輸出了 P2 和 P3 的結果呢? 這是因為,盡管遇到了P1就reject了,然而 P2 和 P3 仍在執行。註意MDN說的是“不管其他Promise是否完成”,而不是“其他Promise被stop”。

let p2 = new Promise((resolve, reject)=> {

setTimeout(resolve, 3000, "P2 resolved");

})

let p3 = new Promise((resolve, reject)=> {

setTimeout(resolve, 4000, "P3 resolved");

})

let pResult = myPromiseAll([p2,55,p3]);

pResult.then(value=>{

console.log(pResult);

console.log(value); // 輸出 [55, 'P2 resolved', 'P3 resolved']

}, err => {

console.log(pResult);

console.log(err);

  • 上一篇:尋找簡單實用的安卓系統小軟件制作方法
  • 下一篇:請問在校大學生怎樣學佛?
  • copyright 2024編程學習大全網