JS 筆記 04:同步、非同步、callback、Promise、async/await

更新於 發佈於 閱讀時間約 7 分鐘

JavaScript 的非同步機制是許多新手卡關的地方,像是 setTimeoutPromiseasync/await 等名詞看起來熟悉,但實際運作卻令人迷惑。這篇文章將循序漸進介紹非同步流程,幫助你了解背後邏輯及日常開發會用到的場景,以及推薦有帥哥的介紹影片。

一、同步與非同步:理解程式的執行順序

為什麼需要非同步?

在程式執行中,有時候某些操作(例如向伺服器取得資料)需要等待結果,但我們不希望整個程式暫停在原地等待。這就是非同步機制的用意。想像你開發一個網站,使用者點擊「取得報價」後,網站會向伺服器請求資料。這個過程是非同步的,因為你不希望整個頁面卡住,只是等回應。

🔍 同步 vs 非同步

  • 同步:每行程式碼照順序執行,等前一行做完才能繼續。
  • 非同步:某些操作可以先暫存,等結果出來再繼續執行。
同步:
┌─────┐ → ┌─────┐ → ┌─────┐
│ A │  │ B │ │ C │

非同步:
┌─────┐ ──> 等待(後續執行)
│ A │
┌─────┐ → ┌─────┐
│ C │ │ D │
↑執行B回來
console.log("A");
console.log("B");
console.log("C");

🔁 結果:A → B → C(同步)

console.log("A");

setTimeout(() => {
console.log("B");
}, 1000);

console.log("C");

結果:A → C → B(非同步)


二、Call stack 和 Event loop:程式是怎麼跑的?

我個人覺得這裡很難懂QQ 因為講者是我的菜,所以我挑了這個影片跟大家介紹

所以說event loop到底是什麼玩意兒?| Philip Roberts | JSConf EU

JavaScript 採用「單執行緒」,表示一次只能處理一個任務。那非同步要怎麼執行?這就涉及 call stack(呼叫堆疊)和 event loop(事件循環)。

程式碼範例:

console.log("Start");

setTimeout(() => {
console.log("Inside setTimeout");
}, 0);

console.log("End");

🔁 輸出結果:

Start End Inside setTimeout

🔍 運作流程

除了在瀏覽器運行程式碼外,還有一個區域叫 web APIs, 可參考影片的11:45處。

  1. "Start" 放入 call stack → 執行 → 移除 (執行完一列就會移除)
  2. setTimeout 被登記進 Web APIs 排隊→ 等候回傳
  3. "End" 放入 call stack → 執行 → 移除
  4. Event loop 檢查 callback queue → 將 "Inside setTimeout" 從隊伍抓出來,加入 call stack → 執行"Inside setTimeout"
  • 更簡單的想,Event loop 就是檢查「還有沒有未跑的程式在排隊」

📦 應用情境

如果我設計了一個 Threads 資料提取程式,資料處理不能卡住主流程,所以要讓它們進入等待區,待主程式清空後再執行。

截圖自 Youtube 影片,注意 event loop 的迴圈運作。

截圖自 Youtube 影片,注意 event loop 的迴圈運作。


raw-image

三、Callback:非同步的起點,但容易造成混亂

Callback把函式當作參數傳入另一個函式裡,等它完成後再執行。這種方式簡單但容易造成「巢狀結構太深」,又稱 Callback Hell。

🧪 範例:

function fetchData(callback) {
setTimeout(() => {
callback("資料拿到了");
}, 1000);
}

fetchData((data) => {
console.log(data);
});

商業應用:如果有多個步驟要執行(例如 Threads API 抓資料 → 分類 → 上傳),用 Callback 一層層包起來,錯誤處理會變得混亂。


四、Promise:解決 Callback 混亂的更好方法

Promise(承諾物件) 是 JavaScript 提供的非同步處理方式,它有三種狀態:

  • Pending(等待中)
  • Resolved(成功)
  • Rejected(失敗)

🧪 範例:

function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功取得資料");
}, 1000);
});
}

fetchData()
.then((res) => console.log(res))
.catch((err) => console.error(err));

🧾 輸出結果:

成功取得資料

🗂️ 用途情境: 在我的 Threads 資料處理流程中,Promise 可以讓我更清楚地分隔資料抓取、處理、儲存等邏輯,也方便加入錯誤攔截機制。


五、async/await + try/catch:非同步流程更好寫

async/await 是 Promise 的語法糖(懶人寫法),讓你可以用看起來像同步的方式寫非同步程式碼。搭配 try/catch 可以完整捕捉錯誤。

🧪 範例:

async function run() {
try {
const result = await fetchData();
console.log(result);
} catch (error) {
console.error("發生錯誤:", error);
}
}

📌 優點說明:

  • 程式碼結構清晰
  • 容易閱讀與維護
  • 錯誤處理一致性高

💡 商業應用場景: 我在使用週末執行自動排程,從 Threads API 抓資料 → 分類 → 儲存至 Google Sheets,再通知用戶。用 async/await 寫這段流程,可以保證每個步驟順利連接,錯誤也能即時攔截。

raw-image




留言
avatar-img
留言分享你的想法!
avatar-img
越南放大鏡 X 下班資工系
26會員
81內容數
雙重身份:越南放大鏡 X 下班資工系 政大東南亞語言學系是我接觸越南語的起點,畢業後找越南外派工作的生活跟資訊時,發現幾乎都是清單式的分享,很難身歷其境。所以我希望「越南放大鏡」可以帶讀者看到更多細節和深入的觀察。 - 下班資工系則是自學資工系的課程內容,記錄實際操作的過程,學習理論的過程。希望可以跟讀者一起成長。
2025/07/27
這篇文章記錄學習 JavaScript 事件冒泡、事件委託、事件傳遞和停止傳遞的筆記,包含基本概念說明、程式碼範例和實際應用案例,並以淺顯易懂的方式說明事件物件 (e) 的用途。
Thumbnail
2025/07/27
這篇文章記錄學習 JavaScript 事件冒泡、事件委託、事件傳遞和停止傳遞的筆記,包含基本概念說明、程式碼範例和實際應用案例,並以淺顯易懂的方式說明事件物件 (e) 的用途。
Thumbnail
2025/06/27
最近在思考把 Threads 貼文轉移到notion變成資料庫跟加上主題編號,但100多篇文真的很懶得複製貼上。於是我參考了以下文章,並搭配 Copilot 把細微的功能修改,約2小時內可完成。這篇文章的目的是補充原作者沒有截圖到的內容,並分享「一鍵擷取」的功能,把第一篇到最新一篇的文全部抓下來。
Thumbnail
2025/06/27
最近在思考把 Threads 貼文轉移到notion變成資料庫跟加上主題編號,但100多篇文真的很懶得複製貼上。於是我參考了以下文章,並搭配 Copilot 把細微的功能修改,約2小時內可完成。這篇文章的目的是補充原作者沒有截圖到的內容,並分享「一鍵擷取」的功能,把第一篇到最新一篇的文全部抓下來。
Thumbnail
2025/06/24
這篇開始進到跟網頁互動較密切相關的單元,我會學習DOM 跟常用的網頁設計指令。練的環境是 VS code,之前的環境是Colab,但Colab比較適合Python。 DOM(Document Object Model),文件物件模型 DOM 是瀏覽器幫你把 網頁HTML 變成 JavaScrip
Thumbnail
2025/06/24
這篇開始進到跟網頁互動較密切相關的單元,我會學習DOM 跟常用的網頁設計指令。練的環境是 VS code,之前的環境是Colab,但Colab比較適合Python。 DOM(Document Object Model),文件物件模型 DOM 是瀏覽器幫你把 網頁HTML 變成 JavaScrip
Thumbnail
看更多
你可能也想看
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
分享一個有趣的套件,名為 await-to-js。 可以讓 Promise 與 await 的寫法更簡潔。
Thumbnail
分享一個有趣的套件,名為 await-to-js。 可以讓 Promise 與 await 的寫法更簡潔。
Thumbnail
JavaScript (簡稱 JS) 是具有一級函數的輕量級、直譯式或即時編譯的程式語言。它因為用作網頁的腳本語言而大為知名,但也用於許多非瀏覽器的環境,像是 Node.js 等。由於 JavaScript 語法上的一些缺點,軟體工程師們又設計出了 CoffeeScript、TypeScript 和
Thumbnail
JavaScript (簡稱 JS) 是具有一級函數的輕量級、直譯式或即時編譯的程式語言。它因為用作網頁的腳本語言而大為知名,但也用於許多非瀏覽器的環境,像是 Node.js 等。由於 JavaScript 語法上的一些缺點,軟體工程師們又設計出了 CoffeeScript、TypeScript 和
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
Thumbnail
簡要說明 JavaScript 的 Event Loop JavaScript 是單執行緒 (single-threaded) 語言,這意味著它一次只能執行一件事,因此所有函式都需要排隊等待執行,這被稱為同步 (synchronous)。在同步操作中,若函式過多或過於複雜,會導致程式阻塞 (blo
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 寫到挑戰六覺得心累ㄌ,向來不是一個可以長久堅持好習慣的人,30 個挑戰聽起來很少,但如果要日復一日堅持下去其實好長r 😮‍💨 挑戰六透過 input 來 filter 從 api 拿回來的資料結
Thumbnail
JavaScript30 傳送門:https://javascript30.com/ 寫到挑戰六覺得心累ㄌ,向來不是一個可以長久堅持好習慣的人,30 個挑戰聽起來很少,但如果要日復一日堅持下去其實好長r 😮‍💨 挑戰六透過 input 來 filter 從 api 拿回來的資料結
Thumbnail
JavaScript是一種具有動態型別、弱型別、原型繼承等特性的高級腳本語言,應用範圍廣泛,包括前端開發、後端開發、移動應用等。它被各種公司和開源社區廣泛使用。學習JavaScript需要掌握ECMAScript標準、異步編程、模塊系統等知識。
Thumbnail
JavaScript是一種具有動態型別、弱型別、原型繼承等特性的高級腳本語言,應用範圍廣泛,包括前端開發、後端開發、移動應用等。它被各種公司和開源社區廣泛使用。學習JavaScript需要掌握ECMAScript標準、異步編程、模塊系統等知識。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News