• 分组操作符
    • buffer
      • 业务场景
    • bufferTime
      • 业务场景
    • groupBy

    分组操作符

    buffer

    buffer() 操作符的函数签名:

    1. buffer([breakObservable])

    buffer 本身意味着我们在等待而不会发出任何值,直到 breakObservable 发生。示例如下:

    1. let breakWhen$ = Rx.Observable.timer(1000);
    2. let stream$ = Rx.Observable.interval(200)
    3. .buffer( breakWhen$ );
    4. stream$.subscribe((data) => console.log( 'values',data ));

    在这个案例中会一次性地发出值: values 0,1,2,3

    业务场景

    Auto complete(自动完成/智能提示) - 使用 buffer() 操作符进行处理的最显著的例子就是 auto complete 。但 auto complete 是如何工作的呢?我们来分步骤看下

    • 用户输入关键字
    • 搜索是基于这些按键的。重要的是,搜索本身是在打字时执行的,要么就执行多次,因为你输入了x个字符,要么采用更普遍的处理方式,就是打字完成后再执行搜索,还可以在输入时进行编辑。那么我们来执行这套解决方案的第一步:
    1. let input = document.getElementById('example');
    2. let input$ = Rx.Observable.fromEvent( input, 'keyup' )
    3. let breakWhen$ = Rx.Observable.timer(1000);
    4. let debounceBreak$ = input$.debounceTime( 2000 );
    5. let stream$ = input$
    6. .map( ev => ev.key )
    7. .buffer( debounceBreak$ );
    8. stream$.subscribe((data) => console.log( 'values',data ));

    我们捕获 keyup 事件。我们还使用了 debounce() 操作符,本质上来说,一旦你停止打字x毫秒后它才会发出值。这个解决方案只是进行中的第一步,因为它只是报告了具体敲击的按键。一个更好的解决方案是捕获输入元素的实际内容,还可以执行 ajax 调用,所以让我们来看一个更精致的解决方案:

    1. let input = document.getElementById('example');
    2. let input$ = Rx.Observable.fromEvent( input, 'keyup' )
    3. let breakWhen$ = Rx.Observable.timer(1000);
    4. let debounceBreak$ = input$.debounceTime( 2000 );
    5. let stream$ = input$
    6. .map( ev => {
    7. return ev.key })
    8. .buffer( debounceBreak$ )
    9. .switchMap((allTypedKeys) => {
    10. // 执行 ajax
    11. console.log('Everything that happened during 2 sec', allTypedKeys)
    12. return Rx.Observable.of('ajax based on ' + input.value);
    13. });
    14. stream$.subscribe((data) => console.log( 'values',data ));

    这个称之为“增强的 auto complete” 。原因如名字一样,我们保存了用户所做的每一个交互,然后才最终决定应该成为 Ajax 调用的最终输入。所以上面代码的结果应该看起来像下面这样:

    1. // 出自 switchMap
    2. Everything that happened during 2 sec ["a", "a", "a", "Backspace", "Backspace", "Backspace", "Backspace", "b", "b", "Backspace", "Backspace", "Backspace", "f", "g", "h", "f", "h", "g"]
    3. // 出自 subscribe
    4. values ajax based on fghfgh

    如你所见,其实我们可以储存大量用户潜在的信息,而不只是做了 auto complete 搜索,我们可以储存他们是如何打字的,这或许很有趣,亦或是很无聊…

    双击 - 在上面的示例中,我已经展示了按组捕获按键可以很有趣,而另一组可能有趣的 UI 事件就是鼠标点击事件,即单击、双击或三连击。如果不用 RxJS 的话,那写出的代码是极不优雅的,反之则轻而易举,像下面这样:

    1. let btn = document.getElementById('btn2');
    2. let btn$ = Rx.Observable.fromEvent( btn, 'click' )
    3. let debounceMouseBreak$ = btn$.debounceTime( 300 );
    4. let btnBuffered$ = btn$
    5. .buffer( debounceMouseBreak$ )
    6. .map( array => array.length )
    7. .filter( count => count >= 2 )
    8. ;
    9. btnBuffered$.subscribe((data) => console.log( 'values',data ));

    多亏 debounce() 操作符,我们可以在发出任何值之前表达等待300毫秒。只是短短几行代码,就让我们很容易的可以决定 filter 应该怎么写。

    bufferTime

    bufferTime() 的函数签名:

    1. bufferTime([ms])

    作用是记录在该时间段内发生的所有事情并输出所有的值。下面的示例是以1秒为时间片段记录输入的所有活动事件。

    1. let input = document.getElementById('example');
    2. let input$ = Rx.Observable.fromEvent( input, 'input' )
    3. .bufferTime(1000);
    4. input$.subscribe((data) => console.log('all inputs in 1 sec', data));

    在这个案例中你得到的输出会是这样的:

    1. all inputs in 1 sec [ Event, Event... ]

    得到的数据似乎没什么用,所以我们可能需要使用 map() 来使数据变得清晰,以便于看到用户实际的按键,像这样:

    1. let input = document.getElementById('example');
    2. let input$ = Rx.Observable.fromEvent( input, 'keyup' )
    3. .map( ev => ev.key)
    4. .bufferTime(1000);
    5. input$.subscribe((data) => console.log('all inputs in 1 sec', data));

    还要注意一点,我把事件改成了 keyup 。现在我们可以看见1秒内发生的所有 keyup 事件。

    业务场景

    如果你想要记录该网站上的其它用户正在做什么,并希望重播他们曾经做过的所有交互,或者当他们开始输入,你希望通过 socket 发送此信息的话,那么上面的示例会非常有用。最后一个是当下的标准功能,你看见一个人在另一个终端上打字。所以确实有这样的业务案例。

    groupBy

    TODO