Promise.all 與 Promise.race

Promise.all 與 Promise.race 的參數值,通常使用陣列結構作為傳入參數,而陣列中要不是就一般的值,要不就是 Promise 物件

Promise.all是"並行運算"使用的靜態方法,它的語法如下(出自MDN):

Promise.all(iterable)

iterable代表可傳入陣列(Array)之類的物件,JavaScript 內建的有實作iterable協定的有 String、Array、TypedArray、Map 與 Set 這幾個物件。一般使用上都用到陣列而已。Promise.all方法會將陣列中的值並行運算執行,全部完成後才會接著下個then方法。在執行時有幾種情況:

  • 陣列中的索引值與執行順序無關

  • 陣列中的值如果不是 Promise 物件,會自動使用Promise.resolve方法來轉換

  • 執行過程中只要有"其中一個(any)"陣列中的 Promise 物件執行發生錯誤例外,或是有 Promise 的 reject 情況,會立即回傳一個 rejected 狀態 promise 物件

  • 實現完成後,接下來的 then 方法會獲取到的值是陣列值

const p1 = Promise.resolve(3)
const p2 = 1337
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('foo'), 1000)
})

Promise.all([p1, p2, p3])
  .then(value => {
    console.log(value)
  })
  .catch(err => {
    console.log(err.message)
  })

//結果: [3, 1337, "foo"]

你可能會好奇,String(字串)類型是可以傳到Promise.all中的參數,傳入後會變成什麼樣子,當然實際上應該沒人這樣在用的。以下為一個簡單的範例:

Promise.all('i am a string')
  .then(value => {
    console.log(value)
  })
  .catch(err => {
    console.log(err.message)
  })

//結果: ["i", " ", "a", "m", " ", "a", " ", "s", "t", "r", "i", "n", "g"]

Promise.race它的真正名稱應該是對比Promise.all的"any",如果對Promise.all來說,指的是"所有的"陣列傳入參數的 Promise 物件都要解決(resolve)完了才進行下一步,Promise.race則是"任何一個"陣列傳入參數的 Promise 物件有解決,就會到下一步去。用"race(競賽)"這個字詞是比喻就像在賽跑一樣,只要有一個參賽者到達終點就行了,當然它的回傳值也只會是那個優勝者而已。

Promise.race的規則與Promise.all相同,只不過實現的話,下一步的then方法只會獲取跑最快的(最快實現的)的那個值,一個簡單的範例如下:

const p1 = Promise.resolve(3)
const p2 = 1337
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('foo'), 1000)
})

Promise.race([p1, p2, p3])
  .then(value => {
    console.log(value)
  })
  .catch(err => {
    console.log(err.message)
  })

上面這個Promise.race範例,你把 p1 與 p2 的位置對調,就會發現最後的結果正好會對調,也就是說正好是只使用Promise.resolve方法的轉換情況,是和陣列中的前後順序有關的。不過因為Promise.race只能選出一個優腃者,p1 與 p2 應該算同時,所以也只能以陣列的順序為順序。

註: 所以用程式範例的結果來說,Promise.race應該要多一個規則,如果陣列中有同時實現的 promise 值,以陣列中的順序優先者為回傳值。

下面的例子是有加上每個陣列中的 Promise 物件產生時間的不同,這當然就只會回傳最快實現的那個 Promise 物件,也就是 p3。

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('p1'), 2000)
})
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('p2'), 1000, 'p2')
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('p3'), 500, 'p3')
})

Promise.race([p1, p2, p3])
  .then(value => {
    console.log(value)
  })
  .catch(err => {
    console.log(err.message)
  })

註: 在 Promises/A+ 並沒有關於Promise.allPromise.race的定義,它們是依據 ES6 Promise 標準的實作。

Last updated