整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ
什麼是 JavaScript 的 Generator Functions (function*)?

前言
function* 是一個比較少人使用但卻非常強大的語法,它允許我們定義一種特殊的函式,稱為「生成器函式」(Generator Function),所以這一篇就要來介紹什麼是 Generator Functions 以及它們的用途。
Generator Functions?
Generator Functions 簡單來講是一個「可以暫停」和「可以恢復」的一個函式,那該怎麼使用呢?其實很簡單,只要在函式宣告的時候,在 function 關鍵字後面加上一個星號 * 即可。
底下是幾個定義 Generator Function 的範例:
1 | |
這邊使用上要注意,Generator Function 並不支援直接使用箭頭函式(Arrow Function),所以我們只能使用傳統的函式宣告或函式表達式來定義 Generator Function。
為什麼需要 Generator Functions?
接下來我們要來看一些為什麼我們會需要使用 Generator Functions 的情境。
通常我們建立一個函式:
1 | |
我們可以看到當我們呼叫了 myFunction 後,函式會從頭到尾執行完畢,無法中途暫停。
但可能我們真正需要的需求是,隨著某些條件的變化,我們希望能夠在函式執行的過程中,暫停並等待下一次的呼叫,這時候 Generator Functions 就派上用場了。
用法也非常簡單:
1 | |
你只需要在你想要暫停的地方使用 yield 關鍵字,這樣當函式執行到 yield 時就會暫停,等待下一次的呼叫。
1 | |
你會發現 gen 並不會像一般函式一樣直接執行,而是回傳一個生成器物件,這個物件有一個 next 方法,每次呼叫 next 都會讓函式從上次暫停的地方繼續執行,直到遇到下一個 yield 或是函式結束。
除此之外 yield 可以搭配回傳值使用,例如 yield value,這樣當你呼叫 next 時,可以取得這個值,所以如果你是習慣撰寫 Pure Function 的開發者,那也可以透過 yield 來達到類似的效果。
1 | |
很有趣吧?你可以隨時呼叫 next 來取得下一個 yield 的值,這樣就能讓函式的執行變得更加靈活。
另外 next 還能夠傳入一個參數,這個參數會成為上一個 yield 表達式的回傳值,這樣就能讓函式在每次恢復執行時,根據外部傳入的值來決定下一步的行為。
1 | |
這裡有一個新手容易搞混的地方:yield 後面的值(Hello, ${name}) 是輸出給外部的(也就是 gen.next().value 拿到的值)。
而變數 task 接收到的,並不是這一行的 Hello...,而是下一次外部呼叫 gen.next("寫程式") 時傳進來的參數。也就是說,外部傳入的 "寫程式" 會取代掉原本暫停的 yield 表達式,賦值給 task。
那還可以在什麼情境下使用 Generator Functions 呢?另一個常見的應用場景是「非同步的 API 呼叫」,透過 Generator Functions 我們可以讓非同步的程式碼看起來像是同步的,這樣就能讓程式碼更容易閱讀和維護。
1 | |
又或者是那種滾動式加載(infinite scrolling)的應用場景,這也可以使用 Generator Functions 來實現:
1 | |
Generator Functions 冷知識
嚴格來說,我們常用的 async/await 其實就是 Generator Functions + Promise + 自動執行器(Auto Runner) 的語法糖。
你剛剛在上面看到的那個 handle 函式,其實就是一個簡易版的自動執行器(類似早期的 co 套件原理)。
async/await 的出現,就是為了幫我們自動處理這些 generator.next() 和 Promise 的串接,讓我們不用自己手寫遞迴,就能優雅地等待非同步結果。
如果你將前面的非同步 API 呼叫的範例改寫成 async/await 的話,就會變成我們熟悉的樣子:
1 | |
只是缺點你就無法像 Generator Functions 那樣,可以隨時暫停和恢復執行,因此如果你有需要這樣的功能,Generator Functions 會是一個不錯的選擇。
雖然現在我們有很方便的 ``async/await`,但在處理記憶體優化(如無限序列)或是複雜的狀態控制(如 Redux-Saga)時,Generator Functions 仍然是無可替代的強大工具哩~
整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ