在ES6中,Promise將我們從「Callback Hell」稍微解放出來
|
|
但Promise也有缺點,例如當asyncFun3需要調用asyncFun1的result時,該怎做呢?可能會用巢狀式Promise,或者用變數暫存每一次的result之類,我們都知道這些不是個好方法
Generator
generator可讓我們的異步流程寫得更synchronous-style,免除了之前的困擾
先用個範例將Promise小改成Generator
|
|
Ln:7的result會收到Ln:3 yield回傳的Promise
待API回傳後,Ln:10 gen.next(data) 會將API回傳的data賦值給result1
但我們不可能一直.then下去,這樣又回到地獄了,所以我們需要一個Function幫我們管理這整個流程,可以自動接著下去做事的傢伙
Co - 知名的TJ大神在幾年前就實現了Generator概念,有興趣的可以參考他的實踐方式,在此我們先寫一個簡易版的管理器用用
|
|
這簡易版的可以協助我們連續的Promise請求,可在這JS Bin Run看看,在此也附上我設定的「任務」Code
|
|
但這樣的流程管理器只能處理都是yield Promise的需求,固我們可以加個工具幫我們判斷是否為Promise
|
|
將isPromise加入到我們的流程管理器 - JS Bin
|
|
對應任務的不同再將流程管理器改造一下就可以用了
進階 (Observable-style)
接下來這章節主要是想將Generator的Iterable-style寫成Observable-style的方式
這表格來自於Kris Kowal’s - GTOR: A General Theory of Reactivity,比較不好理解的部分是Iterable/Observable的差別
Iterable是pull value,Observable是push value
Interable
Generator通過next()來pull value
|
|
Observable
而所謂的Observable通常是指Value「可使用」後,會有通知/訂閱機制(subscription/notification)將Value送出去
在此我們要將流程管理器抽象化成Observable模式
|
|
co管理器多了.subscribe()
,就跟Rx’Library中的Observable一樣,並且接收三個Function作為參數
原本的迭代器next()
也要改動一下
因為是簡易版,所以沒有加上errorHandler
|
|
這樣當每次Value「可使用」後,我們會直接push到onNext()
去,這邊任務的範例是會接收一個Array of name,去call API得到這個name的Github user
|
|
再來是產生一個偽-Observable
對象
|
|
這樣就完成了(完整的JS Bin)!而這樣做的好處就是…
你會發現RxJS原來這麼好用
結語
其實co()
在這就是個「迭代器(Iterator)」角色,讓我們不用一直像以下這樣做
|
|
也可以直接看Co.js的原始碼,並不複雜
看到這裡,希望你對Generator有更深的認識,或許也會對ES7 async/await
和 RxJS
存在的用意更有感觸~
Reference
The Hidden Power of ES6 Generators
Teaching RxJS
初探ES6 Generators