Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/internal/webstreams/writablestream.js
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,13 @@ function writableStreamFinishErroring(stream) {
writableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
return;
}
// The closed promises are only rejected once the sink's abort algorithm
// settles, so materialize them here: deriving them from the 'errored'
// state within that window would hand out an already rejected promise.
stream[kState].closedPromise ??= PromiseWithResolvers();
const writer = stream[kState].writer;
if (writer !== undefined)
writer[kState].close ??= PromiseWithResolvers();
PromisePrototypeThen(
stream[kState].controller[kAbort](abortRequest.reason),
() => {
Expand Down
42 changes: 42 additions & 0 deletions test/parallel/test-webstreams-writer-closed-abort-pending.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use strict';

// The writer's closed promise stays pending until the sink's abort()
// algorithm settles, even when it is first observed after the stream has
// already reached the 'errored' state.

const common = require('../common');
const assert = require('assert');
const { setImmediate: immediate } = require('timers/promises');
const { WritableStream } = require('stream/web');

async function main() {
const error = new Error('boom');
const { promise: abortComplete, resolve: finishAbort } = Promise.withResolvers();
const ws = new WritableStream({
abort: common.mustCall((reason) => {
assert.strictEqual(reason, error);
return abortComplete;
}),
});
const writer = ws.getWriter();
const aborted = writer.abort(error);

// Lets the stream finish erroring and call the sink's abort().
await immediate();

let closedSettled = false;
const closed = writer.closed.catch(common.mustCall((reason) => {
closedSettled = true;
assert.strictEqual(reason, error);
}));

await immediate();
assert.strictEqual(closedSettled, false);

finishAbort();
await aborted;
await closed;
assert.strictEqual(closedSettled, true);
}

main().then(common.mustCall());
Loading