iT邦幫忙

1

JavaScript - Promise 與 async / await

  • 分享至 

  • xImage
  •  

在現代 JavaScript 與 Next.js 全端開發中,Promise 是處理非同步作業(如:API 請求、讀寫資料庫、計時器)的基石。這份筆記將帶你從零開始,完整掌握 Promise 的觀念、語法與實戰應用。


什麼是 Promise?

想像你去速食店點餐:

  1. 你付錢點了一杯飲料,店員給你一張號碼牌(Promise)
  2. 這張號碼牌代表「你未來會拿到飲料」,但目前飲料還在做。
  3. 在等待的過程中你可以去做別的事(非同步、不阻塞)。
  4. 最終會有兩種結果:
  • 成功(Fulfilled):叫到你的號碼,拿到飲料。
  • 失敗(Rejected):店員告知今日珍珠賣完了(發生錯誤)。

回到 JavaScript,要想理解 Promise,就需要先理解 JS 的執行環境:「單執行緒(Single-threaded)」
JavaScript 引擎在同一個時間點只能做一件事情。
如果今天去發送一個網路請求(API 呼叫)需要花費 3 秒鐘,按照傳統同步程式碼的邏輯,整個網頁的畫面會直接「卡死(Blocking)」3 秒鐘,使用者會無法點擊按鈕或滾動頁面。

為了不讓網頁卡死,JavaScript 需要一種機制:「我先送出請求,不擋住後面的程式碼,等資料回來後,你再通知我來拿。」

這個機制就是非同步(Asynchronous),而 Promise 就是這個非同步機制的「資料結構化具現化」。

Promise 的三種狀態

一個 Promise 物件必然處於以下三種狀態之一:

  • Pending(等待中):初始狀態,非同步任務正在執行。
  • Fulfilled(已實現):任務順利完成,並回傳了結果(透過 resolve)。
  • Rejected(已拒絕):任務執行失敗,並回傳了錯誤原因(透過 reject)。

Promise 的狀態一旦從 Pending 轉變成 Fulfilled 或 Rejected 之後,就 定格 Settled 了,無法再變更。


建立與使用

我們可以透過 new Promise 建構子來建立一個 Promise 物件。它會接收一個執行函式(Executor Function),該函式帶有兩個參數:resolve(成功時呼叫)與 reject(失敗時呼叫)。

1. 基礎寫法範例

const checkInventory = (item) => {
  return new Promise((resolve, reject) => {
    // 模擬非同步操作(例如:查詢資料庫)
    setTimeout(() => {
      const stock = { apple: 5, banana: 0 };
      
      if (stock[item] > 0) {
        resolve(`成功!${item} 還有庫存:${stock[item]} 個`);
        } else {
        reject(new Error(`抱歉,${item} 已經賣完了!`));
        }
    }, 1000);
  });
};

2. 使用 Promise:.then().catch()

當我們拿到一個 Promise 實例後,可以用 .then() 接收成功結果,用 .catch() 捕捉錯誤:

checkInventory('apple')
  .then((res) => {
    console.log(res); // 1 秒後印出:"成功!apple 還有庫存:5 個"
  })
  .catch((err) => {
    console.error(err.message);
  })
  .finally(() => {
    console.log("查詢結束(無論成功與否都會執行)");
  });


async / await

雖然 .then() 可以串接非同步任務,但當任務一多容易造成「回呼地獄(Callback Hell)」。在現代 JS/TS 與 Next.js 開發中,我們會使用 async/await 語法糖來讓非同步程式碼看起來像同步程式碼。

回呼地獄https://hyc.eshachem.com/program/js-callback-hell/

async function handleOrder() {
  try {
    // 透過 await 等待 Promise 完成
    const result = await checkInventory('apple');
    console.log(result);
  } catch (error) {
    // 等同於 .catch()
    console.error("發生錯誤啦:", error.message);
  } finally {
    console.log("流程結束");
  }
}

handleOrder();

小結

現在很多工程師都會習慣直接用async / await,我一開始學習也是學async / await,但為了自己的目標想要成為更厲害的Next.js全端工程師,所以我決定開始來探討『為什麼』,第一個令我非常好奇的,就是這個async / await語法糖,也因此研究到Promise,就順便整理、寫了這篇文章~希望對你在前端、全端學習上有幫助!


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言