RxJS的另外四種實現方式(五)——使用生成器實現
js的生成器一般情況下使用場景很少,開發者接觸的不是很多。不瞭解的可以先行檢視js語法瞭解。
這裡把其中的執行順序圖解一下
呼叫方 資料來源
next(value)---------------------------------------> 開始執行生成器函式體
<-------------------------------------------------yield value2
next(value3)--------------------------------------->
<-------------------------------------------------yield value4
next(value5)--------------------------------------->
<-------------------------------------------------return value6
以上是正常返回最後值的過程,也可以永遠不return,變成一個無限生成資料的過程。
另一種情況是提前終止
呼叫方 資料來源
next(value)---------------------------------------> 開始執行生成器函式體
<-------------------------------------------------yield value2
next(value3)--------------------------------------->
<-------------------------------------------------yield value4
return()--------------------------------------->
這種情況下相當於主動關閉生成器。
可以向資料來源的函式發出錯誤:
呼叫方 資料來源
next(value)---------------------------------------> 開始執行生成器函式體
<-------------------------------------------------yield value2
next(value3)--------------------------------------->
<-------------------------------------------------try catch
throw(err)
以上各種行為都可以對應Rx,那麼生成器和Rx的最大區別是什麼呢?
就是誰是主動方,誰是被動方。在生成器中,呼叫方是主動方,相當於主動pull資料,而Rx中,資料來源是主動方,相當於主動push資料。(這裡和Rx中的推拉模式有區別)
那麼如何使用生成器實現Rx呢?其實你估計已經想到了,就是反過來即可:
Observable Observer
next(value)---------------------------------------> 開始執行生成器函式體
<-------------------------------------------------yield value2(得到返回值是value3)
next(value3)--------------------------------------->
<-------------------------------------------------yield value4(返回值是value5)
next(value5)--------------------------------------->
<-------------------------------------------------return value6()
done==true
於是我們就得到了由Observable主動推送過來的資料了。
我們還是以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就是迭代器例項,我們主動呼叫next傳送資料
這裡我們判斷了next函式的返回值裡面的done屬性,如果Observer主動取消訂閱了(在生成器函式裡面執行了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是一個生成器,呼叫它時傳入下一級的迭代器(Observer)
yeild 0 不斷獲取上一級的Observable的資料,一旦收到_done,立即跳出迴圈,並將_done傳入sink中。
最後是實現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
是一個死迴圈,直到收到_done,或者丟擲異常。
至此,我們的Rx的基本功能已經實現,由於生成器的效能較差,所以本人沒有花很多時間去完善各種操作符,只作為一種可以實現的方式展示出來。
下一篇我們介紹最後一種實現方法。
相關文章
- 面試題 LazyMan 的Rxjs實現方式面試題JS
- 五種方式實現 Java 單例模式Java單例模式
- Spring實現IOC容器的兩種實現方式Spring
- LRU演算法四種實現方式介紹演算法
- 純CSS實現四種方式文字反差色效果CSS
- springAOP的三種實現方式Spring
- 單例模式的五種實現方式及優缺點單例模式
- 盤點用jQuery框架實現“for迴圈”的四種方式!jQuery框架
- 關於執行緒池的五種實現方式,七大引數,四種拒絕策略執行緒
- 實踐作業的一種實現方式
- 實現 JavaScript 沙箱的幾種方式JavaScript
- 通過Rxjs五行程式碼實現EventBusJS行程
- 使用Vue實現圖片上傳的三種方式Vue
- 快速排序的四種python實現排序Python
- 九種方式實現跨域跨域
- AOP 有幾種實現方式?
- 實現登入態的幾種方式
- js實現繼承的三種方式JS繼承
- Laravel 路由版本實現的一種方式Laravel路由
- java幾種代理模式的實現方式Java模式
- Android 截圖實現的幾種方式Android
- JS 繼承的 六 種實現方式JS繼承
- 分散式鎖的多種實現方式分散式
- 分散式鎖的幾種實現方式~分散式
- 互動投影的幾種實現方式
- 實現微前端的十種方式 【第一種】前端
- 實現微前端的十種方式 【第二種】前端
- 使用 RxJs 實現一個支援 infinite scroll 的 Angular ComponentJSAngular
- 【設計模式】實現執行緒安全單例模式的五種方式設計模式執行緒單例
- 動畫的另外一種方式動畫
- 多種跨域方式實現原理跨域
- 九種跨域方式實現原理跨域
- 兩種方式實現輪播圖
- Artisan 命令列 2種實現方式命令列
- SpringBoot實現熱部署兩種方式!Spring Boot熱部署
- python 三種方式實現截圖Python
- 單例模式:5種實現方式單例模式
- 使用生成器 --實現迭代協議協議