接上篇RxJS的另外四種實現方式(序)html
想到這個庫的緣由,是看了callbag庫想到的,callbag庫的原理你們能夠本身找資料瞭解,我就很少贅述,我只談談個人理解。callbag的設計思路是把消費者和生產者合併成一個,經過互相傳遞一個回調函數實現通信。看過部分操做符實現原理的同窗確定以爲邏輯十分難解,由於過多的回調使得你的腦回路不夠用了。我用了一些庫函數後,我意識到,其實不須要如此複雜的設計,爲何呢?請看下文函數
callbag裏面有不少代碼是重複書寫的,緣由很簡單,功能是肯定的,如訂閱功能,這是必不可少的操做,下面我來比較一下個人庫的實現和callbag的實現。性能
先上callbag的源碼ui
const interval = period => (start, sink) => { if (start !== 0) return; let i = 0; const id = setInterval(() => { sink(1, i++); }, period); sink(0, t => { if (t === 2) clearInterval(id); }); }; export default interval;
說明一下設計
if(start!=0)return
這句話在callbag實現庫裏面隨處可見,我就是由於這句話引發的思考,爲何每次都要重複寫呢?
固然是由於這是一個生產者,只發送數據,不會去接受數據。code
sink(0, t => { if (t === 2) clearInterval(id); });
上面這段代碼實際上是實現了一個取消訂閱功能,實現方法是向傳來的回調函數再傳回一個回調函數,估計讀者腦子要燒糊了。htm
上面這個interval可觀察對象的原型能夠表明大多數的callbag的案例,那麼有沒有辦法用更爲簡潔的方式實現呢?對象
exports.interval = period => n => { let i = 0; const id = setInterval(() => n(i++), period) return () => clearInterval(id) }
什麼,只有這麼幾行代碼嗎?,沒錯,這就是我認爲實現代碼最小的庫了,不服來戰。此代碼不只小,性能好,還通俗易懂。固然我仍是得稍微解釋一下要使得interval(1000)
成爲一個地道的生產者,必需要實現能夠訂閱,能夠取消訂閱,以及能夠獲得生產者發出的數據(有些還須要獲得complete和error事件,interval不會complete也不會error)blog
interval(1000)
將獲得一個函數n=>……
,這個函數接受一個next函數用於發送數據interval(1000)
這個高階函數等同於「訂閱」,此處是重點(代替了callbag中發送type爲0的行爲)固然interval不會獨立工做,咱們須要更多的操做符和觀察者使得庫來運做。事件
下面是callbag的實現
const filter = condition => source => (start, sink) => { if (start !== 0) return; let talkback; source(0, (t, d) => { if (t === 0) { talkback = d; sink(t, d); } else if (t === 1) { if (condition(d)) sink(t, d); else talkback(1); } else sink(t, d); }); }; module.exports = filter;
依然出現了
if(start!=0)return
沒錯,由於filter只用於被訂閱,自己做爲數據響應者,有人說不對,filter須要對上一級的源作響應,沒錯,因此須要訂閱上一級的源,但傳入的不是自身,而是另外一個回調函數來響應,不然就會有問題。核心代碼就一句,卻須要一大堆代碼來維持正常運行,我看不下去了。
exports.filter = f => source => (n, c) => source(d => f(d) && n(d), c)
What?就一行代碼?你沒看錯,你沒看錯,你沒看錯!
我來解釋一下,這一行代碼。filter是一個操做符,filter(d=>d>1)
表明我只接受大於1的數據,這個將返回一個source=>……
的函數,這個函數接受一個source做爲上一級數據源,能夠是上文的interval(1000)
這樣的生產者,也能夠是其餘操做符。因此
const obserable = filter(d => d > 1)(interval(1000))
你將獲得一個(n,c)=>……
的函數,這個就是可觀察者,你能夠傳入next函數n,和complete函數c來進行「訂閱」了
const disposable = obserable(d => console.log('獲得',d),err => console.log('完成'))//err表明有錯誤,這裏先不處理
你訂閱事後會獲得一個函數disposable,用於「取消訂閱」
disposable()//取消訂閱
這個filter表明了最小庫的精髓:disposable能夠從箭頭函數一路返回,在filter中是隱含的,無需顯示實現而表明complete的c函數也是直接透傳,無需更改。惟獨須要操做的就是next函數,須要向source傳一個新的next函數。當知足條件時就向下一級的next函數發送數據,不然啥也不幹。
(未完待續)