all方法 手写promise_实现Promise.allSettled
離上次寫了 Promise.all 實現之后,已經隔了,呃,快一年了...
為什么又想起來寫 Promise 的其他靜態方法的實現呢?原因是最近已經連續兩次收到了某跳動公司的面試邀請了。想著雖然不一定去面,但還是要把一些面試的八股文給熟悉一下,畢竟又寫了快一年的業務代碼了,自己的長進也是模模糊糊,好像也沒有落到具體的東西上...
首先我們先回顧下 Promise.all 靜態方法的實現
rencoo:[面試題]實現Promise.all?zhuanlan.zhihu.com記得當時寫完之后,知乎上有個哥們 Rambo 還熱心地指出我的問題,并且他自己也寫了更加完美的實現
Rambo:Promise.all實現?zhuanlan.zhihu.com接下來呢,我們就來看看現在要實現的 Promise.allSettled 靜態方法
還是從它的用法入手:
相對于 Promise.all 需要所有 promise都成功時才 resolve或者有一個失敗時即reject,Promise.allSettled 只關心所有 promise 是不是都被 settle 了,不管其是 rejected狀態的 promise,還是非 rejected狀態(即fulfilled)的 promise, 我都可以拿到它的最終狀態并對其進行處理
Promise.allSettled 的結果數組中可能包含以下兩種格式的數據
- {status:"fulfilled", value:result} 對于成功的響應
- {status:"rejected", reason:error} 對于 error
參照原理寫的 Promise.all 的實現,我們根據 Promise.allSettled 的概念,稍作改變就可以寫出實現
if (!Promise.allSettled) {Promise.allSettled = function (promises) {return new Promise(resolve => {const data = [], len = promises.length;let count = len;for (let i = 0; i < len; i += 1) {const promise = promises[i];promise.then(res => {data[i] = { status: 'fulfilled', value: res };}, error => {data[i] = { status: 'rejected', reason: error };}).finally(() => { // promise has been settledif (!--count) {resolve(data);}});}});} }測試下
const promise1 = Promise.resolve(3); const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo')); const promises = [promise2, promise1];Promise.allSettled(promises).then((results) => results.forEach((result) => console.log(result.status)));// expected output: // "rejected" // "fulfilled"另外,更加簡便的,我們也可以根據 Promise.all 來實現 Promise.allSettled
思路是讓 Promise.all 入參中的所有 promise 都映射為新的最終狀態為 fulfilled 的 promise (而新promise的result則根據原來promise的狀態為fulfilled/reject來決定),這樣就總是能讓Promise.all 成功返回數組
if (!Promise.allSettled) {Promise.allSettled = function (promises) {return Promise.all(promises.map(p => Promise.resolve(p).then(res => {return { status: 'fulfilled', value: res }}, error => {return { status: 'rejected', reason: error }})));}; }最后,再對之前 Promise.all 的實現做個修正!!! 當時的實現有誤,對所有 promise 是否都被 settled 的判斷是錯誤的,不能用結果的長度來判斷。把原來的那幾個測試 promise 順序一顛倒就能看出問題來了,最后一個最快被 settled,按照長度來判定的話就 resolve 出去了,但這樣是不對的,因為最后的那個 promise 最快 settled 時,前面幾個慢的還沒有被 settled,這時候時不能 resolve 最終結果的
function all(promises) {let len = promises.length, res = []// 修正let count = lenif (len) {return new Promise(function (resolve, reject) {for(let i=0; i<len; i++) {let promise = promises[i];promise.then(response => {res[i] = response// 當返回結果為最后一個時// 修正// if (res.length === len) {if (!--count) {resolve(res)}}, error => {reject(error)})}})} }// test let p1 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(1)// reject(new Error('error 1'))}, 3000) })let p2 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(2)}, 2000) })let p3 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(3)}, 1000) })all([p1, p2, p3]).then(res => {console.log(res) //(*) }).catch(console.log) // 修正前*處 // console:[empty × 2, 3] // 修正后*處 // console: [1, 2, 3]最后想說的是,技術是件嚴謹的事情,我們需要對自己的輸出有責任心,捂臉...
總結
以上是生活随笔為你收集整理的all方法 手写promise_实现Promise.allSettled的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 夏日信号枪在哪里 美的夏日文案
- 下一篇: hobby store什么意思