欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

字節(jié)飛書面試promise.all實現(xiàn)示例

 更新時間:2022年06月14日 17:35:18   作者:滑稽鴨  
這篇文章主要為大家介紹了字節(jié)飛書面試promise.all實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

金三銀四,身為大四即將成為畢業(yè)生的我迫不及待地將簡歷投進了字節(jié)的飛書部門,本想著掂量一下幾斤幾兩,沒想到這一掂就露餡了??,去大廠的夢想就這么跌倒在了Promsie.all上。但年輕人總是要有斗志的,從哪里跌到就從哪里爬起來!下面是復盤時間。

何為Promise.all?

Promise.all 是 es6 Promise 對象上的一個方法,它的功能就是將多個Promise實例包裝成一個promise實例。以下是 MDN 對 Promise.all 的描述:

Promise.all() 方法接收一個 promise 的 iterable 類型(注:Array,Map,Set都屬于ES6的iterable類型)的輸入,并且只返回一個Promise實例, 那個輸入的所有 promise 的 resolve 回調(diào)的結(jié)果是一個數(shù)組。這個Promise的 resolve 回調(diào)執(zhí)行是在所有輸入的 promise 的 resolve 回調(diào)都結(jié)束,或者輸入的 iterable 里沒有 promise 了的時候。它的 reject 回調(diào)執(zhí)行是,只要任何一個輸入的 promise 的 reject 回調(diào)執(zhí)行或者輸入不合法的 promise 就會立即拋出錯誤,并且reject的是第一個拋出的錯誤信息。

我戴上我的300度近視眼鏡,仔細地提取出這段描述中的關(guān)鍵字:

  • Promise.all 的返回值是一個新的 Promise 實例。
  • Promise.all 接受一個可遍歷的數(shù)據(jù)容器,容器中每個元素都應是 Promise 實例。咱就是說,假設這個容器就是數(shù)組。
  • 數(shù)組中每個 Promise 實例都成功時(由pendding狀態(tài)轉(zhuǎn)化為fulfilled狀態(tài)),Promise.all 才成功。這些 Promise 實例所有的 resolve 結(jié)果會按照原來的順序集合在一個數(shù)組中作為 Promise.all 的 resolve 的結(jié)果。
  • 數(shù)組中只要有一個 Promise 實例失敗(由pendding狀態(tài)轉(zhuǎn)化為rejected狀態(tài)),Promise.all 就失敗。Promise.all 的 .catch() 會捕獲到這個 reject。

原生 Promise.all 測試

咱先看看原生的Promise.all的是啥效果。

const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 延時一秒')
  }, 1000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3 延時兩秒')
  }, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p5 rejected 延時1.5秒')
  }, 1500)
})
// 所有Promise實例都成功
Promise.all([p1, p2, p3])
  .then(res => {
    console.log(res)
  })
  .catch(err => console.log(err)) // 2秒后打印 [ 'p1', 'p2 延時一秒', 'p3 延時兩秒' ]
// 一個Promise實例失敗
Promise.all([p1, p2, p4])
  .then(res => {
    console.log(res)
  })
  .catch(err => console.log(err)) // p4 rejected
// 一個延時失敗的Promise
 Promise.all([p1, p2, p5])
  .then(res => {
    console.log(res)
  })
  .catch(err => console.log(err)) // 1.5秒后打印 p5 rejected
// 兩個Promise實例失敗
Promise.all([p1, p4, p5])
  .then(res => {
    console.log(res)
  })
  .catch(err => console.log(err)) // p4 rejected

注意

上面 p4 和 p5 在未傳入 Promise.all 時需要注釋掉,因為一個調(diào)用了 reject 的 Promise 實例如果沒有使用 .catch() 方法去捕獲錯誤會報錯。但如果 Promise 實例定義了自己的 .catch,就不會觸發(fā) Promise.all 的 .catch() 方法。

OK,理論存在,實踐開始!

手動實現(xiàn)Promise.all

Promise.all 接受一個數(shù)組,返回值是一個新的 Promise 實例

Promise.MyAll = function (promises) {
  return new Promise((resolve, reject) => {
  })
}

數(shù)組中所有 Promise 實例都成功,Promise.all 才成功。不難想到,咱得需要一個數(shù)組來收集這些 Promise 實例的 resolve 結(jié)果。但有句俗話說得好:“不怕一萬,就怕萬一”,萬一數(shù)組里面有元素不是 Promise咋辦 —— 那就得用 Promise.resolve() 把它辦了。這里還有一個問題,Promise 實例是不能直接調(diào)用 resolve 方法的,咱得在 .then() 中去收集結(jié)果。注意要保持結(jié)果的順序。

Promise.MyAll = function (promises) {
  let arr = []
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
      Promise.resolve(item).then(res => {
        arr[i] = res
      })
    }) 
  })
}

將收集到的結(jié)果(數(shù)組arr)作為參數(shù)傳給外層的 resolve 方法。這里咱們肯定是有一個判斷條件的,如何判斷所有 Promise 實例都成功了呢?新手容易寫出這句代碼(沒錯就是我本人了??):

if (arr.length === promises.length) resolve(arr)

咱仔細想想 Promise 使用來干嘛的 —— 處理異步任務。對呀,異步任務很多都需要花時間呀,如果這些 Promise 中最后一個先完成呢?那 arr 數(shù)組不就只有最后一項了,前面的所有項都是 empty。所以這里咱們應該創(chuàng)建一個計數(shù)器,每有一個 Promise 實例成功,計數(shù)器加一:

Promise.MyAll = function (promises) {
  let arr = [],
    count = 0
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
      Promise.resolve(item).then(res => {
        arr[i] = res
        count += 1
        if (count === promises.length) resolve(arr)
      })
    })
  })
}

最后就是處理失敗的情況了,這里有兩種寫法,第一種是用 .catch() 方法捕獲失?。?/p>

Promise.MyAll = function (promises) {
  let arr = [],
    count = 0
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
      Promise.resolve(item).then(res => {
        arr[i] = res
        count += 1
        if (count === promises.length) resolve(arr)
      }).catch(reject)
    })
  })
}

第二種寫法就是給 .then() 方法傳入第二個參數(shù),這個函數(shù)是處理錯誤的回調(diào)函數(shù):

Promise.MyAll = function (promises) {
  let arr = [],
    count = 0
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
      Promise.resolve(item).then(res => {
        arr[i] = res
        count += 1
        if (count === promises.length) resolve(arr)
      }, reject)
    })
  })
}

測試案例

致此 Promise.all 大功告成,趕緊拿來測試一下(摩拳擦掌):

const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 延時一秒')
  }, 1000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3 延時兩秒')
  }, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p5 rejected 延時1.5秒')
  }, 1500)
})
// 所有 Promsie 都成功
Promise.MyAll([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 2秒后打印 [ 'p1', 'p2 延時一秒', 'p3 延時兩秒' ]
// 一個 Promise 失敗
Promise.MyAll([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p4 rejected
// 一個延時失敗的 Promise
Promise.MyAll([p1, p2, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 1.5秒后打印 p5 rejected 延時1.5秒
// 兩個失敗的 Promise
Promise.MyAll([p1, p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p4 rejected

“OhOhOhOh~~~~”,與原生的 Promise.all運行結(jié)果不能說很像,只能說一模一樣。老話說的好,趁熱打鐵——正在火候上。我打開某個學習網(wǎng)站(MDN Web Docs (mozilla.org)),了解到 Promise 對象用于同時處理多個 Promise 的方法還有 Promise.race、Promise.any、Promise.allSettle。從小老師就教會了咱們舉一反三,仔細看了這三個方法的描述之后,我還真給反出來了??。

Promise.race

Promise.race 從字面意思理解就是賽跑,以狀態(tài)變化最快的那個 Promise 實例為準,最快的 Promise 成功 Promise.race 就成功,最快的 Promise 失敗 Promise.race 就失敗。

咱來看看原生 Promise.race 效果

原生 Promise.race 測試

const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 延時一秒')
  }, 1000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3 延時兩秒')
  }, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p5 rejected 延時1秒')
  }, 1500)
})
// p1無延時,p2延時1s,p3延時2s
Promise.race([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1
// p4無延時reject
Promise.race([p4, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p4 rejected
// p5 延時1.5秒reject,p2延時1s
Promise.race([p5, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 1s后打印: p2 延時一秒

理論存在,實踐開始

手寫Promise.race

整體流程與 Promise 差不多,只是對數(shù)組中的 Promise 實例處理的邏輯不一樣,這里我們需要將最快改變狀態(tài)的 Promise 結(jié)果作為 Promise.race 的結(jié)果,相對來說就比較簡單了,代碼如下:

Promise.MyRace = function (promises) {
  return new Promise((resolve, reject) => {
    // 這里不需要使用索引,只要能循環(huán)出每一項就行
    for (const item of promises) {
      Promise.resolve(item).then(resolve, reject)
    }
  })
}

測試案例

還是剛才幾個案例,咱就不重復寫了??

// p1無延時,p2延時1s,p3延時2s
Promise.MyRace([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1
// p4無延時reject
Promise.MyRace([p4, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p4 rejected
// p5 延時1.5秒reject,p2延時1s
Promise.MyRace([p5, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 1s后打印: p2 延時一秒

可以看到,結(jié)果與原生的 Promise.race 是一致的,成功!

Promise.any

Promise.any 與 Promise.all 可以看做是相反的。Promise.any 中只要有一個 Promise 實例成功就成功,只有當所有的 Promise 實例失敗時 Promise.any 才失敗,此時Promise.any 會把所有的失敗/錯誤集合在一起,返回一個失敗的 promise 和AggregateError類型的實例。MDN 上說這個方法還處于試驗階段,如果 node 或者瀏覽器版本過低可能無法使用,各位看官自行測試下。

原生 Promise.any 測試

const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 延時一秒')
  }, 1000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3 延時兩秒')
  }, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p5 rejected 延時1.5秒')
  }, 1500)
})
// 所有 Promise 都成功
Promise.any([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1
// 兩個 Promise 成功
Promise.any([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1
// 只有一個延時成功的 Promise
Promise.any([p2, p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p2 延時1秒
// 所有 Promise 都失敗
Promise.any([p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // AggregateError: All promises were rejected

可以看出,如果 Promise.any 中有多個成功的 Promise 實例,則以最快成功的那個結(jié)果作為自身 resolve 的結(jié)果。

OK,理論存在,實踐開始

手寫Promise.any

依葫蘆畫瓢,咱們先寫出 Promise.any 的整體結(jié)構(gòu):

Promise.MyAny = function (promises) {
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
    })
  })
}

這里跟Promise.all 的邏輯是反的,咱們需要收集 reject 的 Promise,也需要一個數(shù)組和計數(shù)器,用計數(shù)器判斷是否所有的 Promise 實例都失敗。另外在收集失敗的 Promise 結(jié)果時咱需要打上一個失敗的標記方便分析結(jié)果。

Promise.MyAny = function (promises) {
  let arr = [],
    count = 0
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
      Promise.resolve(item).then(resolve, err => {
        arr[i] = { status: 'rejected', val: err }
        count += 1
        if (count === promises.length) reject(new Error('沒有promise成功'))
      })
    })
  })
}

這里我沒有使用 MDN 上規(guī)定的 AggregateError 實例,手寫嘛,隨心所欲一點,寫自己看著舒服的??

測試案例

// 所有 Promise 都成功
Promise.MyAny([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1
// 兩個 Promise 成功
Promise.MyAny([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1
// 只有一個延時成功的 Promise
Promise.MyAny([p2, p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p2 延時1秒
// 所有 Promise 都失敗
Promise.MyAny([p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 沒有promise成功

Promise.allSettled

有時候,咱代碼人總是會有點特殊的需求:如果咱希望一組 Promise 實例無論成功與否,都等它們異步操作結(jié)束了在繼續(xù)執(zhí)行下一步操作,這可如何是好?于是就出現(xiàn)了 Promise.allSettled。

原生 Promise.allSettled 測試

const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 延時一秒')
  }, 1000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3 延時兩秒')
  }, 2000)
})
const p4 = Promise.reject('p4 rejected')
const p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p5 rejected 延時1.5秒')
  }, 1500)
})
// 所有 Promise 實例都成功
Promise.allSettled([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) 
// [
//   { status: 'fulfilled', value: 'p1' },
//   { status: 'fulfilled', value: 'p2 延時一秒' },
//   { status: 'fulfilled', value: 'p3 延時兩秒' }
// ]
// 有一個 Promise 失敗
Promise.allSettled([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err))
// [
//   { status: 'fulfilled', value: 'p1' },
//   { status: 'fulfilled', value: 'p2 延時一秒' },
//   { status: 'rejected' , value: 'p4 rejected' }
// ]
// 所有 Promise 都失敗
Promise.allSettled([p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err))
// [
//   { status: 'rejected', reason: 'p4 rejected' },
//   { status: 'rejected', reason: 'p5 rejected 延時1.5秒' }
// ]

可以看到,與 Promise.any 類似,Promise.allSettled 也給所有收集到的結(jié)果打上了標記。而且 Promise.allSettled 是不會變成 rejected 狀態(tài)的,不管一組 Promise 實例的各自結(jié)果如何,Promise.allSettled 都會轉(zhuǎn)變?yōu)?fulfilled 狀態(tài)。

OK,理論存在,實踐開始

手寫 Promise.allSettled

咱就是說,得用個數(shù)組把所有的 Promise 實例的結(jié)果(無論成功與否)都收集起來,判斷收集完了(所有 Promise 實例狀態(tài)都改變了),咱就將這個收集到的結(jié)果 resolve 掉。收集成功 Promise 結(jié)果的邏輯咱們在 Promise.all 中實現(xiàn)過,收集失敗 Promise 結(jié)果咱們在 Promise.any 中處理過。這波,這波是依葫蘆畫瓢——照樣。

Promise.MyAllSettled = function (promises) {
  let arr = [],
    count = 0
  return new Promise((resolve, reject) => {
    promises.forEach((item, i) => {
      Promise.resolve(item).then(res => {
        arr[i] = { status: 'fulfilled', val: res }
        count += 1
        if (count === promises.length) resolve(arr)
      }, (err) => {
        arr[i] = { status: 'rejected', val: err }
        count += 1
        if (count === promises.length) resolve(arr)
      })
    })
  })
}

這代碼,邏輯上雖說沒問題,但各位優(yōu)秀的程序員們肯定是看不順眼的,怎么會有兩段重復的代碼捏,不行,咱得封裝一下。

Promise.MyAllSettled = function (promises) {
  let arr = [],
    count = 0
  return new Promise((resolve, reject) => {
    const processResult = (res, index, status) => {
      arr[index] = { status: status, val: res }
      count += 1
      if (count === promises.length) resolve(arr)
    }
    promises.forEach((item, i) => {
      Promise.resolve(item).then(res => {
        processResult(res, i, 'fulfilled')
      }, err => {
        processResult(err, i, 'rejected')
      })
    })
  })
}

perfect,俗話說得好:沒病走兩步。老樣子,給代碼跑幾個案例。

測試案例

// 所有 Promise 實例都成功
Promise.MyAllSettled([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) 
// [
//   { status: 'fulfilled', value: 'p1' },
//   { status: 'fulfilled', value: 'p2 延時一秒' },
//   { status: 'fulfilled', value: 'p3 延時兩秒' }
// ]
// 有一個 MyAllSettled 失敗
Promise.allSettled([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err))
// [
//   { status: 'fulfilled', value: 'p1' },
//   { status: 'fulfilled', value: 'p2 延時一秒' },
//   { status: 'rejected' , value: 'p4 rejected' }
// ]
// 所有 MyAllSettled 都失敗
Promise.allSettled([p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err))
// [
//   { status: 'rejected', reason: 'p4 rejected' },
//   { status: 'rejected', reason: 'p5 rejected 延時1.5秒' }
// ]

致此,大功告成,我可以驕傲地對媽媽說:“媽媽,我再也不怕 Promise.all”了

結(jié)語

這次字節(jié)飛書面試對我來說是一個巨大的機遇,第一次體驗面大廠的感覺,可能有暴躁老哥要說了:“字節(jié)面試題就這?你是水文章騙贊的吧”。害,沒辦法,主要是我太菜了,從代碼不知為何物到現(xiàn)在前端學習者,爾來8月右一周矣,水平確實比較次,面試官比較和善,就沒有為難我,問的問題都比較基礎。但我仍然收獲頗豐,感謝字節(jié)團隊,感謝前端這個包容、進步的環(huán)境,我會好好總結(jié)這次面試,盡可能地提升自己,加油!

參考文章

因為實現(xiàn)不了Promise.all,一場面試涼涼了 

Promise 對象 - ECMAScript 6入門 (ruanyifeng.com)

更多關(guān)于字節(jié)面試promise.all的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論