From 7c4f9a34ae9b1cc670a37c830bdea870707891d3 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Wed, 10 Nov 2021 10:14:48 +0200 Subject: [PATCH] stream: allow calling callback before promise Refs: https://github.com/nodejs/node/issues/39535 PR-URL: https://github.com/nodejs/node/pull/40772 Reviewed-By: Matteo Collina Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- lib/internal/streams/destroy.js | 8 ++++-- lib/internal/streams/writable.js | 8 ++++-- .../test-stream-construct-async-error.js | 24 +---------------- .../test-stream-writable-final-async.js | 26 +++++++++++++++++++ 4 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 test/parallel/test-stream-writable-final-async.js diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js index 7d3657443e6ab5..efa09e05eafef0 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -292,10 +292,14 @@ function constructNT(stream) { then.call( result, function() { - process.nextTick(onConstruct, null); + if (!called) { + process.nextTick(onConstruct, null); + } }, function(err) { - process.nextTick(onConstruct, err); + if (!called) { + process.nextTick(onConstruct, err); + } }); } } diff --git a/lib/internal/streams/writable.js b/lib/internal/streams/writable.js index 727e7ede71f8aa..38bfea52a15bfd 100644 --- a/lib/internal/streams/writable.js +++ b/lib/internal/streams/writable.js @@ -699,10 +699,14 @@ function callFinal(stream, state) { then.call( result, function() { - process.nextTick(onFinish, null); + if (!called) { + process.nextTick(onFinish, null); + } }, function(err) { - process.nextTick(onFinish, err); + if (!called) { + process.nextTick(onFinish, err); + } }); } } diff --git a/test/parallel/test-stream-construct-async-error.js b/test/parallel/test-stream-construct-async-error.js index 1c647235e29429..ea2d8740e29c94 100644 --- a/test/parallel/test-stream-construct-async-error.js +++ b/test/parallel/test-stream-construct-async-error.js @@ -9,26 +9,6 @@ const { const { setTimeout } = require('timers/promises'); const assert = require('assert'); -{ - class Foo extends Duplex { - async _construct(cb) { - // eslint-disable-next-line no-restricted-syntax - await setTimeout(common.platformTimeout(1)); - cb(); - throw new Error('boom'); - } - } - - const foo = new Foo(); - foo.on('error', common.expectsError({ - message: 'boom' - })); - foo.on('close', common.mustCall(() => { - assert(foo._writableState.constructed); - assert(foo._readableState.constructed); - })); -} - { class Foo extends Duplex { async _destroy(err, cb) { @@ -98,9 +78,7 @@ const assert = require('assert'); const foo = new Foo(); foo.write('test', common.mustCall()); - foo.on('error', common.expectsError({ - code: 'ERR_MULTIPLE_CALLBACK' - })); + foo.on('error', common.mustNotCall()); } { diff --git a/test/parallel/test-stream-writable-final-async.js b/test/parallel/test-stream-writable-final-async.js new file mode 100644 index 00000000000000..5571b794fd4fbd --- /dev/null +++ b/test/parallel/test-stream-writable-final-async.js @@ -0,0 +1,26 @@ +'use strict'; + +const common = require('../common'); +const { + Duplex, +} = require('stream'); +const { setTimeout } = require('timers/promises'); + +{ + class Foo extends Duplex { + async _final(callback) { + // eslint-disable-next-line no-restricted-syntax + await setTimeout(common.platformTimeout(1)); + callback(); + } + + _read() {} + } + + const foo = new Foo(); + foo._write = common.mustCall((chunk, encoding, cb) => { + cb(); + }); + foo.end('test', common.mustCall()); + foo.on('error', common.mustNotCall()); +}