Search code examples
node.jsecmascript-6promiseeventemitter

Combine Promise and EventEmitter


I have create this "simple pattern" that works for combine Promise and EventEmitter (with nodejs).

But: I'm wondering if there is a better way score a goal?

const { EventEmitter } = require('events');
const fs = require('fs');

function doSomething(parameters) {
  const emitter = new EventEmitter();

  const promise = new Promise((resolve, reject) => {
    // DO DIRTY JOB
    fs.readdir(parameters.directory, (err, files) => {
      if (err) {
        reject(err);
        return;
      }
      files.forEach(file => emitter.emit('update-event', file));
      resolve(`I'm done: ${parameters.param} world`);
    });
  });
  return { promise, emitter };
}

const work = doSomething({ param: 'hello', directory: './' });
work.emitter.on('update-event', data => console.log(`Update ${data}`));
work.promise.then(console.log).catch(console.error);

I was thinking like:

doSomething(...).on(...).then(...)

but I can't figure out how do that.


Solution

  • Node.js has built a function for this: the require('events').once function! Here the PR.

    It has been released with Node [v11.13] (https://nodejs.org/en/blog/release/v11.13.0/)

    An example usage (from docs):

    const { once, EventEmitter } = require('events');
    async function run() {
      const ee = new EventEmitter();
      process.nextTick(() => {
        ee.emit('myevent', 42);
      });
      const [value] = await once(ee, 'myevent');
      console.log(value); // 42
    
      const err = new Error('kaboom');
      process.nextTick(() => {
        ee.emit('error', err);
      });
    
      try {
        await once(ee, 'myevent');
      } catch (err) {
        console.log('error happened', err);
      }
    }
    
    run();