Skip to content

doc: AsyncGenerator + Writable + unhandled exception #29397

@ronag

Description

@ronag

Given the examples of using async generators with writable streams https://nodejs.org/dist/latest-v12.x/docs/api/stream.html#stream_piping_to_writable_streams_from_async_iterators.

There seems to be an issue in that they can cause an unhandled exception if 'error' is emitted after 'finish' (which is currently possible in some cases even with core streams). once will release the 'error' handler on completion ('finish'). I would personally discourage using it as in the example, i.e.

I would replace:

UNSAFE

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

const writable = fs.createWriteStream('./file');

(async function() {
  const readable = Readable.from(iterator);
  readable.pipe(writable);
  // Ensure completion without errors.
  await once(writable, 'finish');
})();

with

SAFE

const finished = util.promisify(stream.finished);

const writable = fs.createWriteStream('./file');

(async function() {
  const readable = Readable.from(iterator);
  readable.pipe(writable);
  // Ensure completion without errors.
  await finished(writable);
})();

or

const pipeline = util.promisify(stream.pipeline);

const writable = fs.createWriteStream('./file');

(async function() {
  const readable = Readable.from(iterator);
  await pipeline(readable, writable);
})();

and

UNSAFE

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

const writable = fs.createWriteStream('./file');

(async function() {
  for await (const chunk of iterator) {
    // Handle backpressure on write().
    if (!writable.write(chunk))
      await once(writable, 'drain');
  }
  writable.end();
  // Ensure completion without errors.
  await once(writable, 'finish');
})();

with

SAFE

const { once } = require('events');
const finished = util.promisify(stream.finished);

const writable = fs.createWriteStream('./file');

(async function() {
  for await (const chunk of iterator) {
    // Handle backpressure on write().
    if (!writable.write(chunk))
      await once(writable, 'drain');
  }
  writable.end();
  // Ensure completion without errors.
  await finished(writable);
})();

Possibly with a note on why once is not appropriate in this situation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    docIssues and PRs related to the documentations.good first issueIssues that are suitable for first-time contributors.streamIssues and PRs related to the stream subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions