Batching events with RxJS
Tags: javascript, node, rxjs
Published: 2022-05-07 09:38:02

---
title: Batching events with RxJS
published: true
description: A concise and simple guide on how to implement event batching for a JavaScript app
tags: js, node, rxjs
---

## What's that
Roughly speaking event batching is accumulating events for some time to process them all at once later.

We can employ two well-known strategies or even combine them to understand when it's time to flush and process the bunch of events buffered:
 - when the number of events reaches a threshold;
 - using an interval — e.g. flush events every 10 seconds.

## Why use it
Event batching could be beneficial for:
 - performance reasons, for example, to reduce the number of writes into persistent storage or to optimize the amount of data transmitted over a network;
 - aggregation — e.g. to group by link and count page visits.

## How to
Implementing event batching in JavaScript with [RxJS](https://rxjs.dev/) is a no-brainer.

Let's start with a Node example.

```javascript
const EventEmitter = require('events');
const { fromEvent, bufferCount } = require('rxjs');

// I assume you already have an instance of EventEmitter in your app. 
// In case I'm wrong, let's create the one.
const eventEmitter = new EventEmitter();

// listen to an event called `something-good-happened`
fromEvent(eventEmitter, 'something-good-happened')
   // accumulate events
  .pipe(
    // and flush them every time it's number reaches 3
    bufferCount(3),
    // let's log it
    tap(() => {
      console.log(
        `Great! The number of good things happened in a row reached ${events.length}. It's time to celebrate.`
      );
      console.log(events);
    })
  )
  // process the batch
  .subscribe((events) => {
    const goodThingsByUser = {};
    for (const event of events) {
        goodThingsByUser[event.userId] = (goodThingsByUser[event.userId] ?? 0) + 1;
    }
    // reportGoodThingsDone(goodThingsByUser);
  });
```

And of course, an example for a browser.

```javascript
import { fromEvent, bufferTime, filter } from "rxjs";

// listen to clicks on the whole document
const clicks$ = fromEvent(
  document.documentElement,
  "click",
  // selecte only properties we need
  (event) => ({
    type: event.type,
    time: new Date(),
    x: event.x,
    y: event.y
  })
);

clicks$
  .pipe(
    // flush events every 1 second
    bufferTime(1000),
    // move next only if there is at least one event
    filter((events) => events.length > 0)
  )
  // process the batch
  .subscribe((events) => {
    fetch("/my-analytics", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(events)
    });
  });
```
One more live example [here](https://codesandbox.io/s/fgr0qb).

Note that there is no silver bullet and each solution has its drawbacks.
Bulk processing of a large bunch of events could dramatically worse the performance of your app because of blocking the main thread, which you should [avoid](https://nodejs.org/en/docs/guides/dont-block-the-event-loop/) at all costs. In case you expect to process lots of data consider using a message queue. Look at [BullMQ](https://docs.bullmq.io/) for example.

Thank you for reading!

Could you share some examples of applying event batching in your projects?