RxJS的另外四种实现方式(一)——代码最小的库

接上篇RxJS的另外四种实现方式(序)html

原由

想到这个库的缘由,是看了callbag库想到的,callbag库的原理你们能够本身找资料了解,我就很少赘述,我只谈谈个人理解。callbag的设计思路是把消费者和生产者合并成一个,经过互相传递一个回调函数实现通信。看过部分操做符实现原理的同窗确定以为逻辑十分难解,由于过多的回调使得你的脑回路不够用了。我用了一些库函数后,我意识到,其实不须要如此复杂的设计,为何呢?请看下文函数

大同小异的callbag

callbag里面有不少代码是重复书写的,缘由很简单,功能是肯定的,如订阅功能,这是必不可少的操做,下面我来比较一下个人库的实现和callbag的实现。性能

对比实现生产者interval

先上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的案例,那么有没有办法用更为简洁的方式实现呢?对象

ShowTime

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的行为)
  • 返回的是一个dispose函数,即用于“取消订阅”的功能(代替了callbag中传回一个回调并在里面接受type为2的行为)
  • 函数中调用了传入的next函数n,即发送出去了数据

固然interval不会独立工做,咱们须要更多的操做符和观察者使得库来运做。事件

对比操做符filter

下面是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须要对上一级的源作响应,没错,因此须要订阅上一级的源,但传入的不是自身,而是另外一个回调函数来响应,不然就会有问题。核心代码就一句,却须要一大堆代码来维持正常运行,我看不下去了。

ShowTime

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函数发送数据,不然啥也不干。

(未完待续)

相关文章
相关标签/搜索