美文网首页
响应式编程实战—— RxJS 暂停事件流与初始值

响应式编程实战—— RxJS 暂停事件流与初始值

作者: du1dume | 来源:发表于2020-06-01 02:02 被阅读0次

    昨天我们讲到开始和停止一个事件流,回顾一下代码:

    const stopBtnClick$ = fromEvent(stopBtnRef.current, "click");
    const startBtnClick$ = fromEvent(startBtnRef.current, "click");
    const perSecond$ = interval(1000);
    
    const intervalCanBeStopped$ = perSecond$
    .pipe(takeUntil(stopBtnClick$));
    
    const subscription = startBtnClick$.pipe(
      switchMapTo(intervalCanBeStopped$)
    ).subscribe(v => console.log(v));
    

    现在的情况是,当我们点击停止按钮后再次点击开始按钮,计数又是从 0 开始。如果我们想从停止时的数字继续计数呢?按照常规的编程模型,我们会这样做:

    let count = 0;
    const subscription = startBtnClick$
    .pipe(
      switchMapTo(intervalCanBeStopped$),
    )
    .subscribe(v => console.log(count++));
    

    这样做,确实可以实现从暂定点开始恢复计数。但:

    不要这样做!!!

    不要这样做!!!

    不要这样做!!!

    在 Rx 编程模型中,正确的做法是使用 scan 操作符。scan 操作符就像是数组的 reduce 函数。它的使用方法是:

    scan((acc, value,index) => acc, seed)

    scan 的参数有两个,一个是累积函数,是必须提供的;另一个是起始值,为可选参数。累积函数中的 acc 参数是累积值,value 是原始流的值,index 是索引,返回值是累计值。返回值会作为下次函数运行的参数。

    具体使用方法如下:

    startBtnClick$
    .pipe(
      switchMapTo(intervalCanBeStopped$),
      scan((acc)=>{count: acc.count + 1}, {count:0})
    )
    

    这里我们没有使用原始流中值,我们的累计值的初始值是个对象,对象里面有个 count 属性,值为 0 : {count:0},也就是对应函数参数中的 acc。累积函数的返回值为累计值中的 count 属性 +1。这样就完成了暂停功能。

    下面我们来看看另一种为 scan 提供初始值的方法。

    startWith:这个操作符的作用是在原始流产生值之前插入提供给它参数值。

    我们的代码改动如下:

    startBtnClick$
    .pipe(
      switchMapTo(intervalCanBeStopped$),
      startWith({count: 0}),
      scan((acc)=>{count: acc.count + 1})
    )
    

    startWith 就像是加塞儿,intervalCanbeStopped$ 产生了第一个值,碰到 startWith 后,startWith 中的参数将加塞到这值之前传递给 scan 。我们知道 scan 操作符在不提供第二个参数时,会使用原始流传递过来的第一个值作为初始值。因此,startWith 中的参数成为了 scan 的初始值。

    今天使用到的两个操作符将在前端中的状态管理,网络请求中经常使用到。今后的文章中会提到。

    如有任何问题,请关注公众号“读一读我”。

    相关文章

      网友评论

          本文标题:响应式编程实战—— RxJS 暂停事件流与初始值

          本文链接:https://www.haomeiwen.com/subject/negdzhtx.html