一個有點邊緣的東西,但學起來還不錯。
簡述
最近想要學習 redux saga 這個東西,如果你聽過這東西的話就應該也知道學 saga 會需要一些 generator
的前備知識。
總之,為了讓接下來學習 redux saga 能夠順利,決定來稍微認識一下這個東西。
什麼是 generator?
我覺得用範例來解釋最快,所以先來看段 code:
1 | function* myGenerator() { |
使用 generator 的方式就是在 function 後面加上一個 *
,雖然也可以加在名稱前面,但我還是偏好加在 function 後面。
接著執行這個 function 時,跟一般的 function 有個最大的不同,就是它不會立即執行每一圈迴圈,跑到迴圈結束為止,而是會被「暫停住」,然後回傳一個 iterable
。
至於什麼是 iterable
?簡單來說,你只要想成每一次我 call iterable.next()
時,它就會找到下一個 yield
的位置,繼續往下執行,直到又碰到下一個 yield
為止。
因為我每一次都是在迭代 yield
這個關鍵字,所以才會說是「iterable(可迭代的)」
另外 next()
有回傳值,內容長這樣:
1 | // typescript |
以剛剛的例子來說你大概就猜的出來用意了,value
就是 yield
後面接的值,而 done
則是用來表示「目前有沒有 yield
?」
順道一提,如果 generator 有 return
回傳值的話,結果就會變這樣:
1 | function* myGenerator() { |
算是一個特例,可以讓你在 done: true
的時候還能拿到 value
,不過一般不會這樣用,這邊只是順便提一下。
這就是關於 generator 的最最最基本的用法。
在 next 中傳入參數
這是另一個在 generator 中很重要的觀念,建議一定要弄懂。
簡單來說,在 next 傳入的參數可以「改寫上一個 yield 的值」,一樣來看例子:
1 | function* myGenerator(x) { |
看起來有夠複雜,但只要照著 code 來一步一步來執行就會好懂一些了:
iterable.next()
因為這是第一個 yield
,所以不傳入參數,5 + 1
得到 6
。
iterable.next(12)
依照剛剛說的,把上一個 yield
後面的值全部改寫,所以就會從 (x + 1)
變成 12
。
接著 const y = 2 * 12
得到 24
,所以目前的 yield
後面的值就會是 8
(24 / 3
)。
iterable.next(13)
一樣把上一個 yield
後面的值全部改寫,所以就會從 y / 3
變成 13
。
最後這次因為是 return
,所以 5 + 24 + 13
得到 42
如果有點難懂的話,可以想成這樣:
1 | function* myGenerator (5) { |
for … of
iteralbe
可以用 for...of
來遍歷 yield
的值:
1 | function* myGenerator() { |
總之呢,我覺得最重要的是一定要分清楚 next()
跟 next(param)
的行為有什麼不同,目前關於 generator 的部分先知道這些就差不多了,剩下的有時間再去研究就好。
最後,如果你想試看看用 generator 來實作「非同步」操作的話,可以參考:從 callback 到 Promise 再到 generator 。