iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Modern Web

Web Bluetooth API 實戰:30 天打造通用 BLE 偵錯工具系列 第 16

Day 16:語法蜜糖 async:讓非同步程式碼更簡潔

  • 分享至 

  • xImage
  •  

今天我們將放慢腳步,回歸到非同步程式設計的起點,專注於一個看似簡單,卻蘊含深意的關鍵字:async

在前幾天的內容中,我們為了快速理解整個流程,將 async/await 視為一個密不可分的整體來學習。這種方法有助於我們快速建立宏觀概念,但魔鬼往往藏在細節裡。今天,我們要像偵探一樣,把它們暫時拆開,單獨審視 async

我們要徹底搞清楚:當我們在一個函式前面,輕輕地加上 async 這個詞,到底對這個函式施了什麼魔法?它為什麼被稱為「語法蜜糖」?它又為什麼是所有 await 操作不可或缺的前提?

今天的目標非常純粹:徹底理解 async 函式的本質。學完今天,你將會明白 async 如何將任何一個普通函式,都轉變為一個「承諾未來的 Promise 製造機」,並為我們明天重新學習 await 打下最堅實的地基。


1. async 的黃金法則

關於 async 函式,你只需要記住一條顛撲不破的黃金法則:

async 函式,永遠、永遠、永遠,回傳一個 Promise。

無論你在函式內部做了什麼,是回傳一個數字、一個字串,還是什麼都不回傳,只要你在 function 前面加上了 async,這個函式的回傳值必定是一個 Promise 物件。


2. 魔法揭秘:async 如何包裝回傳值

async 這個關鍵字就像一個自動化的「Promise 包裝工廠」。讓我們看看它是如何處理不同情況的。

情況一:回傳一個「普通值」

讓我們定義一個最簡單的 async 函式,它只回傳一個字串。

// 在 function 前面加上 async
async function sayHello() {
  return 'Hello, World!';
}

// 呼叫這個函式,並看看回傳的是什麼
const result = sayHello();

console.log(result);

打開開發者工具的 Console,你會看到驚人的結果:

Promise {<fulfilled>: "Hello, World!"}

我們並沒有手動建立 Promise,但 result 卻是一個 Promise!

  • 魔法解析:JavaScript 引擎看到 async 關鍵字,它就在內部自動幫我們做了這件事:它拿到了 'Hello, World!' 這個普通字串,然後把它打包成一個已經完成 (fulfilled) 的 Promise 再回傳出來。

  • 如何取出裡面的值? 既然回傳的是 Promise,我們就可以用之前學過的 .then() 來取得結果:

    sayHello().then(value => {
      console.log('用 .then() 取出的值:', value); // 輸出: 用 .then() 取出的值: Hello, World!
    });
    

情況二:在函式中「拋出錯誤」

如果 async 函式在執行過程中出錯了呢?

async function somethingGoesWrong() {
  console.log('這行會執行...');
  throw new Error('糟糕,出錯了!');
  // console.log('這行永遠不會執行');
}

const errorResult = somethingGoesWrong();

console.log(errorResult);

再次查看 Console,你會看到:

這行會執行...
Promise {<rejected>: Error: 糟糕,出錯了!}

同時,瀏覽器可能還會印出一個未被捕獲的錯誤訊息。

  • 魔法解析async 函式非常聰明。它內建了 try...catch 的機制。當它發現函式內部拋出了錯誤,它會自動捕獲這個錯誤,然後將它打包成一個已經被拒絕 (rejected) 的 Promise 回傳出來。

  • 如何處理這個錯誤? 同樣地,我們可以使用 .catch() 來優雅地處理這個被拒絕的 Promise:

    somethingGoesWrong().catch(error => {
      console.error('用 .catch() 捕獲的錯誤:', error.message); // 輸出: 用 .catch() 捕獲的錯誤: 糟糕,出錯了!
    });
    

3. 為什麼我們需要 async

既然 async 只是把東西包裝成 Promise,我們為什麼不自己手動包裝呢?async 作為「語法蜜糖」,到底甜在哪裡?

  1. 語意清晰,提升可讀性 當你在一個函式簽名上看到 async,它就像一個醒目的路標,立刻告訴閱讀程式碼的人(包括未來的你):「注意!這個函式內部包含了非同步邏輯,它的回傳值是一個 Promise,請用非同步的方式來處理它。」這讓程式碼的意圖一目了然。

  2. await 創造了唯一的「合法環境」 這是 async 最最重要、無可替代的作用。我們將在明天深入探討的 await 關鍵字,有一個非常嚴格的規定:

    await 只能在 async 函式內部使用。

    你可以把 async 函式想像成一個特殊的「異次元空間」,只有在這個空間裡,時間才可以被 await「暫停」。async 關鍵字的作用,就是開啟這個空間的「傳送門」。沒有 async,就沒有 await


總結與後續

今天我們進行了一次深入的顯微鏡觀察,專注於 async 這一個關鍵字
現在,我們已經徹底理解了 async 函式這個強大的「容器」。明天,我們將重新拿起它的最佳拍檔——await 關鍵字。
我們將學習如何在 async 函式這個專屬的「異次元空間」中,使用 await 來優雅地「暫停」和「等待」Promise 的結果,並用 try...catch 來確保我們程式的健壯性。

那麼今天的內容就到這邊,感謝你能看到這裡,在這邊祝你早安、午安、晚安,我們明天見。


上一篇
Day 15:現代非同步解方 (2):Promise Chaining 串連探索步驟
下一篇
Day 17:終極武器 await:用同步思維,駕馭非同步探索流程
系列文
Web Bluetooth API 實戰:30 天打造通用 BLE 偵錯工具22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言