iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
Modern Web

前端藏寶圖系列 第 17

Promise

前言

不知道大家學習英語的時候有沒有過明明語法規則都記清楚了,卻還是不清楚實際如何運用的經驗,或是只能死記文法書上的句子,遇到變化的情形就不知所措(怎麼好像是要賣英文課程XD

上述的經驗想必大家或多或少都曾經歷過,而我在學習 Promise 的時候也有同樣的感受。/images/emoticon/emoticon06.gif

以下嘗試在認識語法後,用生活實例練習 Promise 的概念

語法與觀念

在蹲馬步學習語法前,必須要知道 Promise 的出現是因為過去用callback 方式來處理非同步事件的順序時,程式碼會有過於巢狀難以閱讀及難維護的現象

Promise的串接特性讓原本多層巢狀的程式碼可以變成單層

而在 ES2017 (ES8) 又出現了async/await,整個演化史簡單呈現如下:

callback hell --> Promise --> async/await

知道整個脈絡後一起來看語法吧!

new Promise( /* executor */ function(resolve, reject) { ... } );

根據MDN的語法規則,Promise 物件接受一個callback function,這個 callback function 接受兩個參數:

  1. resolve 函式
  2. reject 函式

Promise 物件會有以下幾種狀態:

  1. pending:初始狀態,不是 fulfilled 與 rejected。
  2. fulfilled:表示操作成功完成。
  3. rejected:表示操作失敗


圖片來源:MDN

根據上圖,Promise物件在建立時是處於 pending 的狀態,之後會有以下兩種可能:

  1. 成功 --> 執行 resolve 函式 --> 狀態由 pending 變成 fulfilled
  2. 發生錯誤 --> 執行 reject 函式 --> 狀態由 pending 變成 rejected

promise 方法

這兩個方法都可以回傳 Promise,可以繼續串接。

  • Promise.prototype.then():接收 resolve 函式的結果
  • Promise.prototype.catch():用來抓取 reject 函式的錯誤原因

日常實例練習

看完語法覺得一切支離破碎的話不如一起跟著生活實例練習看看~(以下範例參考 Wes Bos 部落格改寫)

想像我們今天去點飲料,店家會給你收據和叫號單,當號碼輪到你的時候才代表飲料做好了,Promise 的概念就類似於那張叫號單,當我們拿到叫號單的時候,代表我們在未來某一刻會拿到點的飲料。

以下在makeDrinks的函式中回傳一個 Promise,用 setTimeout 模擬等待店家製作飲料的時間。

function makeDrinks(drinksName) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`這是你點的${drinksName}`);
    }, 2000);
  });
}

// 一張叫號單
const bubbleTeaPromise = makeDrinks("珍珠奶茶");

console.log(bubbleTeaPromise); // 印出一個Promise物件


// 用.then() 取得結果
bubbleTeaPromise.then((drinks) => {
   console.log(drinks);
});

// 這是你點的珍珠奶茶

現在模擬店家收到三張訂單,必須依照來電先後順序製作

makeDrinks("珍珠奶茶")
  .then((drinks) => {
    console.log(drinks);
    return makeDrinks("英式紅茶");
  })
  .then((drinks) => {
    console.log(drinks);
    return makeDrinks("美式咖啡");
  })
  .then((drinks) => {
    console.log(drinks);
  });
  
//這是你點的珍珠奶茶
//這是你點的英式紅茶
//這是你點的美式咖啡

假設店家今天的招牌ironman冬瓜檸檬賣完了,店員便會取消訂單,在程式碼上增加了 reject 函式,如果有客人點了這個品項就會執行,Promise轉為rejected狀態,並執行 catch 流程

function makeDrinks(drinksName) {
  return new Promise((resolve, reject) => {
    if (drinksName.includes("ironman")) {
      reject("ironman冬瓜檸檬賣完了");
    }
    setTimeout(() => {
      resolve(`這是你點的${drinksName}`);
    }, 2000);
  });
}


makeDrinks("美式咖啡")
  .then((drinks) => {
    console.log(drinks);
    return makeDrinks("珍珠奶茶");
  })
  .then((drinks) => {
    console.log(drinks);
    return makeDrinks("ironman冬瓜檸檬");
  })
  .then((drinks) => {
    console.log(drinks);
  })
  .catch((err) => {
    console.log(err);
  });
  
  
//這是你點的美式咖啡
//這是你點的珍珠奶茶
//ironman冬瓜檸檬賣完了

結語

經過這次寫文章學習,對於 Promise 的理解大約從 1.5% 提升到 55% 左右,期許之後理解程度可以再提升至 87%

如果有任何錯誤的地方也請高手們指教了,感謝~/images/emoticon/emoticon41.gif

參考資料:
MDN
Promises


上一篇
同步與非同步
下一篇
Promise 方法
系列文
前端藏寶圖30

尚未有邦友留言

立即登入留言