Skip to content

events: timing issue awaiting multiple events emitted in same nextTick #32431

Closed
@jasnell

Description

@jasnell

Just leaving this here as an issue worth investigating. Not sure there's anything we can do about it other than documenting it...

Multiple events emitted on the same process.nextTick() may be missed when using await once(). For example, when running the following, both the 'bar' and 'foo' events are emitted but the async function foo() never completes because await once(myEE, 'foo') occurs after the foo event is actually emitted.

'use strict';

const { EventEmitter, once } = require('events');

const myEE = new EventEmitter();

async function foo() {
  await once(myEE, 'bar');
  console.log('bar');

  await once(myEE, 'foo');
  console.log('foo');
}

process.nextTick(() => {
  myEE.emit('bar');
  myEE.emit('foo');
});

foo().then(() => console.log('done'));

setTimeout(() => {}, 1000);

The only way to catch both events is to use Promise.all() or Promise.allSettled(), or to not use await with once(myEE, 'bar')

'use strict';

const { EventEmitter, once } = require('events');

const myEE = new EventEmitter();

async function foo() {
  await once(myEE, 'bar');
  console.log('bar');

  await once(myEE, 'foo');
  console.log('foo');
}

async function foo2() {
  await Promise.all([once(myEE, 'bar'), once(myEE, 'foo')]);
  console.log('foo', 'bar');
}

process.nextTick(() => {
  myEE.emit('bar');
  myEE.emit('foo');
});

foo2().then(() => console.log('done'));

setTimeout(() => {}, 1000);

Why does this happen? It is because the process.nextTick is processed before the microtask queue. Both events are emitted synchronously before the microtask queue is processed. The await once(myEE, 'bar') does not continue until the microtask queue is executed, after the 'foo' event is emitted, so await once(myEE, 'foo') ends up waiting forever, having missed the actual event.

Metadata

Metadata

Assignees

No one assigned

    Labels

    docIssues and PRs related to the documentations.eventsIssues and PRs related to the events subsystem / EventEmitter.promisesIssues and PRs related to ECMAScript promises.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions