Published on

[學習筆記] JS 非同步處理:Promise 建構函式與物件方法

Promise 物件是為了解決非同步事件的問題,像是一個等待非同步操作完成的物件,事件完成時,Promise 會根據操作結果是成功或失敗來做後續的相應處理。

狀態改變之後就會被固定,永遠不會再改變

最早的 JS 非同步語法 XMLHttpRequest 的可讀性很差,函式會是巢狀的結構,Promise 就是用來優化非同步的語法,而最常見的實踐就是 fetch() web api,他讓非同步語法結構類似於同步語言,更好讀也更好管理。

Promise 的建構函式

Promise 本身是一個建構函式,使用 new Promise() 來建立物件。

Promise 物件的參數為一個包含兩個參數 (resolve, reject) 的 callback function,成功的狀況下就會執行 resolve(value),失敗則執行 reject(error),像是在 callback 裡面自己執行 if/else

new Promise( (resolve, reject){} )

resolve 和 reject 都有一個回傳值,可以把 resolve 後的值透過 .then 繼續傳遞下去,reject 的回傳值則通常是錯誤訊息。

Promise.all()Promise.race()

函式本身是物件的一種,因此 Promise 建構函示也有自己的方法可以使用,這邊介紹兩個比較常用、也容易被拿來比較的兩個方法:Promise.all()Promise.race()

這兩個 Promise 物件方法,都是可以讓多個 Promise 同時進行。差別在於回傳值,以及是否一定會將所有的 Promise 跑完。

Promise.all() 會在所有的 Promise 都結束之後才回傳,回傳值是一個陣列,而且如果有任一個 Promise 被拒絕,Promise.all() 就會失敗

Promise.race() 會在任一個 Promise 有回傳值時(不論是成功或失敗),就結束整個行程,忽略掉其他的 Promise

Promise.all()

  • 可以讓多個 promise 同時開始進行,但回傳值會依原本順序呈現
  • 接收一個可迭代的物件做為參數,通常是 promise 物件組成的陣列
  • 會依序在每個 promise 完成時,將 resolve 的值存入陣列中
  • 所有的 promise 都 resolve 才會回傳 resolve 陣列,若其中有一個 promise 被拒絕,整個 Promise.all 就會被拒絕
const promise1 = Promise.resolve(1)
const promise3 = 2
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve(3), 1000)
})

Promise.all([promise1, promise2, promise3])
  .then((values) => {
    console.log('所有 Promise 都已完成:', values) // [1, 2, 3]
  })
  .catch((error) => {
    console.error('至少有一個 Promise 失敗:', error)
  })

Promise.race()

  • 同樣接收一個可迭代的物件做為參數
  • 任何一個 promise 狀態改變(最早轉變的),就會回傳該 promise 物件成功或失敗的訊息 (resolve 或 reject)
  • 有接收到回傳值後,其餘 promise 的結果或錯誤都會被忽略
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1 完成'), 2000)
})

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2 完成'), 1000)
})

Promise.race([promise1, promise2])
  .then((result) => {
    console.log('最快完成的 Promise:', result) // Promise 2 完成
  })
  .catch((error) => {
    console.error('至少有一個 Promise 失敗:', error)
  })

Promise 物件的方法

Promise 建構出的物件有三個方法,是讓我們可以在 Promise 結束之後繼續執行後續的動作,這三個方法必須在 new 出一個 Promise 物件後才能呼叫

  • then():Promise 執行結果是 resolve 的話就會接續執行 .then() 裡的程式
  • catch():如果執行結果是 reject,就會跳到 catch 繼續執行
  • finaly():不論成功或失敗都會回傳

可以把 Promise 執行後的回傳值當作 then 的參數,在 then() 的程式就可以使用該值,catch() 也可以接收參數使用,參數通常是 event

const fetchData = () => {
  return new Promise((resolve, reject) => {
    // 用 setTimeout 模擬非同步
    setTimeout(() => {
      const data = { message: 'Hello, world!' }
      resolve(data)
    }, 2000)
  })
}

// 使用 Promise
fetchData()
  .then((result) => {
    console.log('成功:', result)
  })
  .catch((error) => {
    console.error('失敗:', error)
  })

除了 Promise 之外,JS 還有許多處理非同步事件的方法,包括現在最常用的 async/await,這就等之後有機會再來筆記啦~

參考資料: