iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
自我挑戰組

Be friend with JavaScript系列 第 23

Day 23 - Promise

Promise 解決了回調地獄,在處理一些需要花費比較長時間的任務時使用 Promise 就可以進行非同步的處理,防止阻塞。

使用方式:
利用 Constructor 製作一個 Promise 物件,且 Promise 會接收一個 function 作為參數,傳遞給 Promise 的 function 有 resolve 和 reject 參數,resolve 表示成功,reject 表示失敗。

// Initialize a promise
const promise = new Promise((resolve, reject) => {})
console.log(promise);

這時候開啟 Devtool 可以看到 PromiseState 為 pending(進行中),表示 resolve 或 reject 之前的初始狀態,因為我們還沒設定 resolve 和 reject 要做啥事。
https://ithelp.ithome.com.tw/upload/images/20210924/20140282MC9JafqCUm.jpg

PromiseState 分為三種:

  • pending - 進行中
  • fulfilled- 操作成功,promise 已解決
  • rejected - 操作失敗,promise 被拒絕

將 Promise 展開,可以看到裡面有 Promise(), catch(), then(), finally()
https://ithelp.ithome.com.tw/upload/images/20210924/20140282yUOYYqVySU.jpg

  • then() 表示處理 resolve
  • catch() 表示處理 reject
  • finally() 當一個 promise 被解決時調用,無論結果是成功或是失敗都會執行。

接著再將 Promise() 這個 constructor 展開,可以發現裡面有許多方法,包含了 resolve(),reject(),race(),all()...等。
https://ithelp.ithome.com.tw/upload/images/20210924/20140282gyK7io61JY.jpg

  • Promise.resolve() 作用為將 PromiseState 由 pending 變成 fulfilled
  • Promise.reject() 作用為將 PromiseState 由 pending 變成 rejected
  • Promise.race() 用於處理多個 Promise,只要有一個成功,就 return 成功結果,其他的被淘汰,如果全部失敗,就 return 失敗
  • Promise.all() 用於處理多個 Promise,如果有其中一個 Promise 失敗全部就失敗,而全部的 Promise 都成功才代表成功。

來舉個簡單的例子~

function fn1(){
  setTimeout(function(){
    console.log(1)
  },0)
}
function fn2(){
  console.log(2)
}
fn1()
fn2()
// 2
// 1

setTimeout() 為非同步事件,即使時間設定 0 秒,JavaScript 也會先跳過它,先往下執行別的動作,最後再回來執行它,所以最終的結果會先印出 2 再印出 setTimeout() 裡的 1。

如果我們想要結果如同執行 function 的順序,先印出 fn1() 再印出 fn2(),可以使用 Promise()。

function fn1() {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      console.log(1);
      resolve(); // 這個 resolve 會決定 fn 什麼時候會進 then
    }, 0)
  })
}
function fn2() {
  console.log(2);
}
fn1().then(fn2); // 執行後 console.log 的順序為 1 => 2
// 1
// 2

再來舉個不只一個 Promise 的例子:

const PROMISE1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("PROMISE1");
  },0)
})

const PROMISE2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("PROMISE2");
  },1000)
})

const RES = Promise.race([PROMISE1,PROMISE2]);
console.log(RES)

上面的例子使用 race(),只要有一個成功最終的結果就是成功,而因為 PROMISE1 執行時就 resolve,所以最後 PromiseState 會顯示 fulfilled。
https://ithelp.ithome.com.tw/upload/images/20210927/20140282bxC8sGTDNn.jpg

將上面的程式碼改一下

const PROMISE1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("PROMISE1");
  },2000)
})

const PROMISE2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("PROMISE2");
  },1000)
})

const RES = Promise.race([PROMISE1,PROMISE2]);
console.log(RES)

因為 PROMISE2 設定的時間比 PROMISE1 短,會先執行 PROMISE2,而 PROMISE2 裡面是 reject,所以最後 PromiseState 會顯示 rejected,且 PromiseResult 為 PROMISE2。
https://ithelp.ithome.com.tw/upload/images/20210927/20140282dioYXcCKzw.jpg

參考資料:
Promise - MDN
Understanding the Event Loop, Callbacks, Promises, and Async/Await in JavaScript


最後推薦一下不錯的資源:


上一篇
Day 22 - Ajax
下一篇
Day 24 - fetch
系列文
Be friend with JavaScript39

尚未有邦友留言

立即登入留言