js的生成器一般情況下使用場景很少肛真,開發(fā)者接觸的不是很多蚓让。不了解的可以先行查看js語法了解历极。
這里把其中的執(zhí)行順序圖解一下
調(diào)用方 數(shù)據(jù)源
next(value)---------------------------------------> 開始執(zhí)行生成器函數(shù)體
<-------------------------------------------------yield value2
next(value3)--------------------------------------->
<-------------------------------------------------yield value4
next(value5)--------------------------------------->
<-------------------------------------------------return value6
以上是正常返回最后值的過程寞肖,也可以永遠不return新蟆,變成一個無限生成數(shù)據(jù)的過程。
另一種情況是提前終止
調(diào)用方 數(shù)據(jù)源
next(value)---------------------------------------> 開始執(zhí)行生成器函數(shù)體
<-------------------------------------------------yield value2
next(value3)--------------------------------------->
<-------------------------------------------------yield value4
return()--------------------------------------->
這種情況下相當(dāng)于主動關(guān)閉生成器帕翻。
可以向數(shù)據(jù)源的函數(shù)發(fā)出錯誤:
調(diào)用方 數(shù)據(jù)源
next(value)---------------------------------------> 開始執(zhí)行生成器函數(shù)體
<-------------------------------------------------yield value2
next(value3)--------------------------------------->
<-------------------------------------------------try catch
throw(err)
以上各種行為都可以對應(yīng)Rx,那么生成器和Rx的最大區(qū)別是什么呢?
就是誰是主動方揩晴,誰是被動方硫兰。在生成器中,調(diào)用方是主動方泳赋,相當(dāng)于主動pull數(shù)據(jù)腮郊,而Rx中衅鹿,數(shù)據(jù)源是主動方,相當(dāng)于主動push數(shù)據(jù)泵三。(這里和Rx中的推拉模式有區(qū)別)
那么如何使用生成器實現(xiàn)Rx呢烫幕?其實你估計已經(jīng)想到了,就是反過來即可:
Observable Observer
next(value)---------------------------------------> 開始執(zhí)行生成器函數(shù)體
<-------------------------------------------------yield value2(得到返回值是value3)
next(value3)--------------------------------------->
<-------------------------------------------------yield value4(返回值是value5)
next(value5)--------------------------------------->
<-------------------------------------------------return value6()
done==true
于是我們就得到了由Observable主動推送過來的數(shù)據(jù)了。
我們還是以interval舉例
exports.interval = period => sink => {
if (sink.next().done) return noop
let i = 0;
const id = setInterval(() => sink.next(i++).done && clearInterval(id), period)
return () => clearInterval(id)
}
這里傳入的sink就是迭代器實例,我們主動調(diào)用next發(fā)送數(shù)據(jù)
這里我們判斷了next函數(shù)的返回值里面的done屬性,如果Observer主動取消訂閱了(在生成器函數(shù)里面執(zhí)行了return語句)那么done就為true
下面是filter操作符:
function* _filter(sink, f) {
for (let done = sink.next().done; !done;) {
let x = yield 0
if (x === _done) break
if (f(x)) done = sink.next(x).done
}
sink.next(_done)
sink.return()
}
exports.filter = f => source => sink => source(_filter(sink, f))
_done是一個Symbol仅炊,用來表示Observable的complete事件
_filter是一個生成器蜕窿,調(diào)用它時傳入下一級的迭代器(Observer)
yeild 0 不斷獲取上一級的Observable的數(shù)據(jù)浙滤,一旦收到_done阴挣,立即跳出循環(huán),并將_done傳入sink中纺腊。
最后是實現(xiàn)Subscriber
function* subscribe(n, e, c) {
while (true) {
try {
let result = yield 0
while (result !== _done) {
if (n(result) === _done) return
result = yield 0
}
c && c()
} catch (err) {
e && e(err)
}
}
}
exports.subscribe = subscribe
是一個死循環(huán)畔咧,直到收到_done茎芭,或者拋出異常。
至此誓沸,我們的Rx的基本功能已經(jīng)實現(xiàn)梅桩,由于生成器的性能較差,所以本人沒有花很多時間去完善各種操作符拜隧,只作為一種可以實現(xiàn)的方式展示出來宿百。
下一篇我們介紹最后一種實現(xiàn)方法。