RxJS的另外四种实现方式(五)——使用生成器实现

Wesley13
• 阅读 716

接上一篇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的基本功能已经实现,由于生成器的性能较差,所以本人没有花很多时间去完善各种操作符,只作为一种可以实现的方式展示出来。

下一篇我们介绍最后一种实现方法。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
RxJS的另外四种实现方式(后记)—— 同时实现管道和链式编程
目录RxJS的另外四种实现方式(序)(https://my.oschina.net/langhuihui/blog/2051754)RxJS的另外四种实现方式(一)——代码最小的库(https://my.oschina.net/langhuihui/blog/2051770)RxJS的另外四种实现方式(二)——代码最小的库(续)
Wesley13 Wesley13
3年前
RxJS的另外四种实现方式(三)——性能最高的库
接上篇RxJS的另外四种实现方式(二)——代码最小的库(续)(https://my.oschina.net/langhuihui/blog/2052019)代码最小的库rx4rxlite虽然在性能测试中超过了callbag,但和most库较量的时候却落败了,于是我下载了most库,要解开most库性能高的原因。我们先上一组测试数据,这是
Wesley13 Wesley13
3年前
RxJS的另外四种实现方式(四)——性能最高的库(续)
接上一篇RxJS的另外四种实现方式(三)——性能最高的库(https://my.oschina.net/langhuihui/blog/2054887)上一篇文章我展示了这个最高性能库的实现方法。下面我介绍一下这个性能提升的秘密。首先,为了弄清楚Most库究竟为何如此快,我必须借助其他工具。比如chrome的devtools性能分析,刚开始
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
RxJS的另外四种实现方式(六)——使用Stream类实现
接上一篇RxJS的另外四种实现方式(五)——使用生成器实现(https://my.oschina.net/langhuihui/blog/2120113)该实现方式与之前几种不同的,该实现方式仅针对Nodejs环境。在Nodejs环境中,提供了Stream类,包括Readable、Transform、Writeable等子类都是可扩展的。从字面
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这