Skip to content

Inconsistent behavior of nextTick and queueMicrotask #51156

@mcollina

Description

@mcollina

Consider this snippet:

const { EventEmitter } = require('node:events')

function run (name) {
  return new Promise((resolve) => {
    const e = new EventEmitter()
    process.nextTick(() => {
      e.emit('error', new Error())
    });
    resolve(e)
  }).then(((e) => {
    e.on('error', err => {
      console.error(`### ${name} ###`, err)
    })
  }))
}

queueMicrotask(run.bind(null, 'queueMicrotask'))
setImmediate(run.bind(null, 'setImmediate'))

This results in

### queueMicrotask ### Error
    at /Users/matteo/c.cjs:7:23
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
node:events:492
      throw er; // Unhandled 'error' event
      ^

Error
    at /Users/matteo/c.cjs:7:23
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
Emitted 'error' event at:
    at /Users/matteo/c.cjs:7:9
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)

Node.js v20.10.0

Why is this an issue? In most part of Node.js core,
we use process.nextTick(() => ee.emit('error')) to let users install event handlers.
However, if an EventEmitter is returned by an async function, there is a significant possibility that the error could not be caught.

(This is essentially a problem for Node.js streams).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions