How to create a RxJS buffer that groups elements in NodeJS but that does not rely on forever running interval?

喜你入骨 提交于 2019-12-17 21:07:03

问题


I'm capturing events from an application using Rx.Observable.fromEvent in a NodeJS. These are sent to another server using request (https://www.npmjs.com/package/request). To avoid a high network load I need to buffer those events at a given timeout between sent requests.

Problem

Using bufferWithTime(200) will keep the node process running and I can't know when the application has finished to close the stream.

Is there any way to use Rx buffers to say:

  1. When Element 1 is pushed set a timer
  2. When Element 2 and 3 arrive before the timer expires push them to an array [1, 2, 3] (the buffer)
  3. When the timer expires, send the [1, 2, 3] array down the pipe.
  4. If Element 4 came after the timer expires then set a new timer and start all over again.

If no element is pushed then no timer is started which would make the process exit.

My initial approach was:

Rx.Observable
     .fromEvent(eventEmitter, 'log')
     .bufferWithTime(200) // this is the issue
     .map(addEventsToRequestOption)
     .map(request)
     .flatMap(Promise.resolve)
     .subscribe(log('Response received'))

回答1:


A proposed implementation, using the delay operator :

function emits(who){
  return function (x) { console.log([who, "emits"].join(" ") + " " + x + " click(s)");};
}

var source = Rx.Observable.fromEvent(document.body, 'click');
console.log("running");

var delayedSource$ = source.delay(1200);

var buffered$ = source
     .buffer(function () { return  delayedSource$;}).map(function(clickBuffer){return clickBuffer.length;})

buffered$.subscribe(emits("buffer"));

jsbin here : http://jsbin.com/wilurivehu/edit?html,js,console,output




回答2:


You'll probably need to split the stream and use the second part to trigger the first.

var source = Rx.Observable.fromEvent(eventEmitter, 'log');
var closer = source.flatMapFirst(Rx.Observable.timer(2000));

source
     .buffer(closer)
     .map(addEventsToRequestOption)
     .flatMap(function(x) { Promise.resolve(request(x)); })
     //I assume this log method returns a function?
     .subscribe(log('Response received'));

source.flatMapFirst(Rx.Observable.timer(2000)) is the important line here. It creates an Observable that generates a timer that will trigger after 2000 ms. When the first event comes in it will kick off the timer. flatMapFirst will ignore subsequent events as long as the timer is running. When the timer finally emits it will trigger the buffer to emit its current buffer and start again.

See docs on buffer with a boundary Observable



来源:https://stackoverflow.com/questions/33402737/how-to-create-a-rxjs-buffer-that-groups-elements-in-nodejs-but-that-does-not-rel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!