線上課程觀課進度管理小工具開發日誌
Day 9:「修煉圈圈 Practice Rings」Web app 開發日誌 - 2025 六角 AI Vibe Coding 體驗營期末大魔王作業
這份筆記旨在記錄 2025 六角 Vibe Coding 體驗營每日作業 Day 21 的期末專案成果,從一個簡單的個人痛點出發,透過與 AI(在我這個情境中是 Perplexity)協作,在一天內完成了一個包含前後端的全端網頁小工具:「修煉圈圈 Practice Rings」。
2025 六角學院 Vibe Coding 體驗營完課心得
透過 2025 六角 Vibe Coding 體驗營,我學會先釐清需求、再和 AI 合作實作,用 SDD 與規格和自己對話,也透過實作看見技術底子哪些地方還需要補強。
線上課程觀課進度管理小工具開發日誌
Day 9:「修煉圈圈 Practice Rings」Web app 開發日誌 - 2025 六角 AI Vibe Coding 體驗營期末大魔王作業
這份筆記旨在記錄 2025 六角 Vibe Coding 體驗營每日作業 Day 21 的期末專案成果,從一個簡單的個人痛點出發,透過與 AI(在我這個情境中是 Perplexity)協作,在一天內完成了一個包含前後端的全端網頁小工具:「修煉圈圈 Practice Rings」。
2025 六角學院 Vibe Coding 體驗營完課心得
透過 2025 六角 Vibe Coding 體驗營,我學會先釐清需求、再和 AI 合作實作,用 SDD 與規格和自己對話,也透過實作看見技術底子哪些地方還需要補強。
<100 subscribers
<100 subscribers
Call Stack;遞迴函數與 call stack 的關係;Task Queue(非同步的概念再釐清)
試著理解遞迴函數運作方式的過程,感覺需要瞭解 JS 如何排序要執行的指令,聯想到 Day1-3 使用 Vitest readline 的時候讀到的非同步和任務排序的概念
查閱文件和科普說明,發現一樣是任務排序但是不同情境的東西:

JavaScript's call stack/event loop/task queue 互動關係的視覺化操作界面: loupe
這個視覺化工具對於理解瀏覽器如何執行被 JavaScript 程式碼定義的行為很有幫助
規劃好程式佇列和任務執行順序,才能有流暢的使用者體驗(不卡頓)
JavaScript 一次只能做一件事(一個程式碼片段),瀏覽器有提供 WebAPI ,透過搭配 event loop 的方式同時處理多個任務
JavaScript 會在 call stack 中依序堆疊要執行的程式碼片段,越往後被呼叫的 function 被堆疊在越上方,會被優先執行並從堆疊中清除。在堆疊中的單一程式碼片段如果執行時間太久,整個流程會全部卡住,此時瀏覽器無法執行任何動作或反應/渲染,稱為 blocking 阻塞。
task queue 會依序排列 WebAPI 處理好的任務,等候排入 call stack 執行。排列順序會按照 Macro/micro task 判斷。
event loop 的作用是去監控堆疊(call stack)和工作佇列(task queue),當堆疊已經完全清空、沒有執行項目的時候,便把佇列中的內容拉到堆疊中去執行。
參考文件
利用 function 內自我呼叫的方式堆疊 call stack 後再回收,以 MDN 官方文件舉例的程式碼來看:
function foo(i) {
if (i < 0) {
return;
}
console.log(`begin: ${i}`);
foo(i - 1);
console.log(`end: ${i}`);
}
foo(3);
步驟 | 呼叫(目前執行的那一層) | call stack(頂端在上) | console.log 結果 | 遞迴呼叫動作 |
|---|---|---|---|---|
1 |
|
|
| 呼叫 |
2 |
|
|
| 呼叫 |
3 |
|
|
最終輸出順序:
begin: 3
begin: 2
begin: 1
begin: 0
end: 0
end: 1
end: 2
end: 3
現代說法通常會分成「task(或 macrotask)queue」和「microtask queue」,是兩個不同的佇列。
整個 JavaScript 程式碼執行順序(就是 event loop 主要在做的事)大致是:
如果 call stack 不為空,就把目前的任務執行到結束(同步程式碼、或某個已經放進 stack 的 task/microtask)。
當 call stack 清空時:
先把 microtask queue 清到空(途中新增的 microtask 也要優先處理完)。
然後從 task(macrotask)queue 取出最舊的一個任務,放進 call stack 執行。
在一輪 task 執行完、microtask queue 清空後,瀏覽器才有機會做一次畫面渲染。
Day1-3 練習 Vitest 有用到 async/await 處理終端機輸入。當程式執行到 await somePromise 時:
async function main() {
const input = await question('請輸入數字:');
// ... 後面的處理
}
先「暫停」目前這個 async 函式,讓它後面的程式碼不要繼續往下跑。
等 somePromise 被 resolve/reject 之後(如使用者輸入數字後),恢復這個 async 函式的後半段執行;這個「恢復動作」會被排進 microtask queue。
其他 microtask handler 和原始的 Promise 寫法還沒練習到。
參考文件來源:
起點:想理解遞迴函數怎麼執行(foo(3) → 2 → 1 → 0 → -1,再一層層往回印出結果)。
發現:遞迴本身只用到 call stack 的同步行為(先進後出),跟非同步任務排序無關——整段遞迴從頭到尾都在同一個 task 裡一次跑完。
延伸:這引導到理解「JS 單執行緒 + event loop」的完整機制:
call stack:存放正在執行的函式,一次只能處理一個任務。
task queue(macrotask):存放 setTimeout、DOM 事件等非同步任務。
microtask queue:存放 Promise handler、async/await 後半段等微任務。
event loop 規則:stack 清空後,先清空 microtask queue,再從 task queue 取下一個任務。
結論:遞迴 = call stack 堆疊與彈出;非同步 = event loop 在不同佇列間排程。兩者分別對應「單一任務內的執行流程」與「任務之間的排程順序」。
這樣整個程式碼執行排序規則大致上就理解了。
Call Stack;遞迴函數與 call stack 的關係;Task Queue(非同步的概念再釐清)
試著理解遞迴函數運作方式的過程,感覺需要瞭解 JS 如何排序要執行的指令,聯想到 Day1-3 使用 Vitest readline 的時候讀到的非同步和任務排序的概念
查閱文件和科普說明,發現一樣是任務排序但是不同情境的東西:

JavaScript's call stack/event loop/task queue 互動關係的視覺化操作界面: loupe
這個視覺化工具對於理解瀏覽器如何執行被 JavaScript 程式碼定義的行為很有幫助
規劃好程式佇列和任務執行順序,才能有流暢的使用者體驗(不卡頓)
JavaScript 一次只能做一件事(一個程式碼片段),瀏覽器有提供 WebAPI ,透過搭配 event loop 的方式同時處理多個任務
JavaScript 會在 call stack 中依序堆疊要執行的程式碼片段,越往後被呼叫的 function 被堆疊在越上方,會被優先執行並從堆疊中清除。在堆疊中的單一程式碼片段如果執行時間太久,整個流程會全部卡住,此時瀏覽器無法執行任何動作或反應/渲染,稱為 blocking 阻塞。
task queue 會依序排列 WebAPI 處理好的任務,等候排入 call stack 執行。排列順序會按照 Macro/micro task 判斷。
event loop 的作用是去監控堆疊(call stack)和工作佇列(task queue),當堆疊已經完全清空、沒有執行項目的時候,便把佇列中的內容拉到堆疊中去執行。
參考文件
利用 function 內自我呼叫的方式堆疊 call stack 後再回收,以 MDN 官方文件舉例的程式碼來看:
function foo(i) {
if (i < 0) {
return;
}
console.log(`begin: ${i}`);
foo(i - 1);
console.log(`end: ${i}`);
}
foo(3);
步驟 | 呼叫(目前執行的那一層) | call stack(頂端在上) | console.log 結果 | 遞迴呼叫動作 |
|---|---|---|---|---|
1 |
|
|
| 呼叫 |
2 |
|
|
| 呼叫 |
3 |
|
|
最終輸出順序:
begin: 3
begin: 2
begin: 1
begin: 0
end: 0
end: 1
end: 2
end: 3
現代說法通常會分成「task(或 macrotask)queue」和「microtask queue」,是兩個不同的佇列。
整個 JavaScript 程式碼執行順序(就是 event loop 主要在做的事)大致是:
如果 call stack 不為空,就把目前的任務執行到結束(同步程式碼、或某個已經放進 stack 的 task/microtask)。
當 call stack 清空時:
先把 microtask queue 清到空(途中新增的 microtask 也要優先處理完)。
然後從 task(macrotask)queue 取出最舊的一個任務,放進 call stack 執行。
在一輪 task 執行完、microtask queue 清空後,瀏覽器才有機會做一次畫面渲染。
Day1-3 練習 Vitest 有用到 async/await 處理終端機輸入。當程式執行到 await somePromise 時:
async function main() {
const input = await question('請輸入數字:');
// ... 後面的處理
}
先「暫停」目前這個 async 函式,讓它後面的程式碼不要繼續往下跑。
等 somePromise 被 resolve/reject 之後(如使用者輸入數字後),恢復這個 async 函式的後半段執行;這個「恢復動作」會被排進 microtask queue。
其他 microtask handler 和原始的 Promise 寫法還沒練習到。
參考文件來源:
起點:想理解遞迴函數怎麼執行(foo(3) → 2 → 1 → 0 → -1,再一層層往回印出結果)。
發現:遞迴本身只用到 call stack 的同步行為(先進後出),跟非同步任務排序無關——整段遞迴從頭到尾都在同一個 task 裡一次跑完。
延伸:這引導到理解「JS 單執行緒 + event loop」的完整機制:
call stack:存放正在執行的函式,一次只能處理一個任務。
task queue(macrotask):存放 setTimeout、DOM 事件等非同步任務。
microtask queue:存放 Promise handler、async/await 後半段等微任務。
event loop 規則:stack 清空後,先清空 microtask queue,再從 task queue 取下一個任務。
結論:遞迴 = call stack 堆疊與彈出;非同步 = event loop 在不同佇列間排程。兩者分別對應「單一任務內的執行流程」與「任務之間的排程順序」。
這樣整個程式碼執行排序規則大致上就理解了。
|
呼叫 |
4 |
|
|
| 呼叫 |
5 |
|
| 無輸出 | 無(直接 return) |
6 | 回到 |
|
| 無(這層遞迴已呼叫過) |
7 |
|
| 無 | 無 |
8 | 回到 |
|
| 無 |
9 |
|
| 無 | 無 |
10 | 回到 |
|
| 無 |
11 |
|
| 無 | 無 |
12 | 回到 |
|
| 無 |
13 |
|
| 無 | 無 |
|
呼叫 |
4 |
|
|
| 呼叫 |
5 |
|
| 無輸出 | 無(直接 return) |
6 | 回到 |
|
| 無(這層遞迴已呼叫過) |
7 |
|
| 無 | 無 |
8 | 回到 |
|
| 無 |
9 |
|
| 無 | 無 |
10 | 回到 |
|
| 無 |
11 |
|
| 無 | 無 |
12 | 回到 |
|
| 無 |
13 |
|
| 無 | 無 |
Share Dialog
Share Dialog
No comments yet