暫停一下再出發!全面解析 JavaScript Generator 實用技巧
什麼是 Generator?
Generator 的基本概念
在現實生活中,很多情境需要我們「做一點事、暫停一下、再繼續做下一點事」,例如:
- 填問卷:先回答前幾題,暫時休息,等想到答案後再繼續填。
- 做菜:準備食材、放進鍋裡煮,等熟了之後再進行下一個步驟。
在程式世界裡,如果我們希望「做一點事、暫停一下、再繼續做下一點事」就需要依賴 Generator。Generator 就像幫我們建立了一個「可隨時暫停和繼續」的函式。透過在函式宣告前面加上 *(例如 function* myGenerator())並在 需要暫停的地方使用 yield 關鍵字,我們就可以一步步地控制這個函式的執行。
function* 與 yieldfunction*:這個宣告方式代表「這是一個生成器函式」,與普通的function最大差別在於,它能透過yield進行暫停與繼續。yield:可以想像成「把工作階段暫停,先把目前結果交出去,等之後再被叫起來繼續做」。程式每次跑到yield就會停住,直到有人呼叫next()才再往下繼續。
以下我們先舉一個簡單的「計數器生成器」範例,帶大家感受一下 Generator 的神奇之處:
function* counter() {
let count = 0;
while (true) {
yield count; // 暫停並返回當前 count
count++;
}
}
const c = counter();
console.log(c.next()); // { value: 0, done: false }
console.log(c.next()); // { value: 1, done: false }
console.log(c.next()); // { value: 2, done: false }
以上的程式中,每次呼叫 c.next(),就像對計數器說:「往下跑一步,並告訴我現在的數字」。
為什麼需要 Generator?
我們已經知道 Generator 可以在函式執行過程中隨時暫停、繼續,那這對我們到底有什麼幫助呢?以下舉幾個常見的使用場景:
-
循序執行(順序產生資料)
假設你在寫一支程式,需要依序產生一大串數字或資料,就像流水線一樣,每做一個就回傳一次給外面使用者。這時候,Generator 可以很直覺地實現「一個一個丟出來」的功能,而不需要一次把所有資料都生成完才回傳。 -
延遲計算(按需計算資料)
在面對龐大的資料或複雜的運算時,有時候我們不想一次算到完,因為那樣可能會非常耗時或耗記憶體。透過 Generator,我們可以在需要用到結果的時候,才去計算下一步。以餐廳廚房出餐作為比喻:通常一般的餐廳不會一次煮好一桌菜才出餐,而是先做好前菜就立即出餐,等待客人吃完再出下一道菜,減少廚房忙亂,也可節省資源。
-
提高程式碼可讀性
在某些需要階段性處理的流程中,如果不用 Generator,可能會寫得一團亂,或需要很多旗標變數來控制執行時機。Generator 讓我們可以在邏輯上更容易地一段一段看,每次yield都代表一個「休息切點」,這樣程式結構會變得較清晰。