diff --git a/index.bs b/index.bs index ced85a05c..bff861430 100644 --- a/index.bs +++ b/index.bs @@ -2649,7 +2649,7 @@ WritableStream(underlyingSink = {}, { size, highWater and put it in an errored state. It should clean up any held resources, much like close, but perhaps with some custom handling. Unlike close, abort will be called even if writes are queued up; those chunks will be thrown away. If this process is asynchronous, it can return a promise to signal - success or failure. If no abort method is passed, by default the close method will be called instead. + success or failure. The controller object passed to start, write and close is an @@ -3321,8 +3321,8 @@ nothrow>WritableStreamDefaultControllerAbort ( controller, reaso 1. Set _controller_.[[queue]] to a new empty List. - 1. Let _sinkAbortPromise_ be ! PromiseInvokeOrFallbackOrNoop(_controller_.[[underlyingSink]], - `"abort"`, « _reason_ », `"close"`, « _controller_ »). + 1. Let _sinkAbortPromise_ be ! PromiseInvokeOrNoop(_controller_.[[underlyingSink]], `"abort"`, « + _reason_ »). 1. Return the result of transforming _sinkAbortPromise_ by a fulfillment handler that returns *undefined*. @@ -3722,30 +3722,6 @@ A few abstract operations are used in this specification for utility purposes. W 1. Return *true*. -

PromiseInvokeOrFallbackOrNoop ( -O, P1, args1, P2, args2 )

- -
- PromiseInvokeOrFallbackOrNoop is a specialized version of promise-calling that works on methods, calls a - fallback method if the first method is not present, and returns a promise for undefined when - neither method is present. -
- - - 1. Assert: _O_ is not *undefined*. - 1. Assert: ! IsPropertyKey(_P1_) is *true*. - 1. Assert: _args1_ is a List. - 1. Assert: ! IsPropertyKey(_P2_) is *true*. - 1. Assert: _args2_ is a List. - 1. Let _method_ be GetV(_O_, _P1_). - 1. If _method_ is an abrupt completion, return a promise rejected with _method_.[[Value]]. - 1. Let _method_ be _method_.[[Value]]. - 1. If _method_ is *undefined*, return ! PromiseInvokeOrNoop(_O_, _P2_, _args2_). - 1. Let _returnValue_ be Call(_method_, _O_, _args1_). - 1. If _returnValue_ is an abrupt completion, return a promise rejected with _returnValue_.[[Value]]. - 1. Otherwise, return a promise resolved with _returnValue_.[[Value]]. - -

PromiseInvokeOrNoop ( O, P, args )

@@ -4085,7 +4061,14 @@ promises returned by its writer's {{WritableS close() { return new Promise((resolve, reject) => { ws.onclose = resolve; - ws.close(); + ws.close(1000); + }); + }, + + abort(reason) { + return new Promise((resolve, reject) => { + ws.onclose = resolve; + ws.close(4000, reason && reason.message); }); } }); @@ -4129,6 +4112,10 @@ an individual write succeeded or failed. close() { return fs.close(fd); + }, + + abort() { + return fs.close(fd); } }); } @@ -4223,7 +4210,14 @@ source abstractions. this._ws.close(); }); } - }); + + abort(reason) { + return new Promise((resolve, reject) => { + ws.onclose = resolve; + ws.close(4000, reason && reason.message); + }); + } + } We can then use the objects created by this function to communicate with a remote web socket, using the standard stream diff --git a/reference-implementation/lib/helpers.js b/reference-implementation/lib/helpers.js index 28a47458e..5f48df1c4 100644 --- a/reference-implementation/lib/helpers.js +++ b/reference-implementation/lib/helpers.js @@ -100,16 +100,6 @@ exports.PromiseInvokeOrPerformFallback = (O, P, args, F, argsF) => { } }; -exports.PromiseInvokeOrFallbackOrNoop = (O, P1, args1, P2, args2) => { - assert(O !== undefined); - assert(IsPropertyKey(P1)); - assert(Array.isArray(args1)); - assert(IsPropertyKey(P2)); - assert(Array.isArray(args2)); - - return exports.PromiseInvokeOrPerformFallback(O, P1, args1, exports.PromiseInvokeOrNoop, [O, P2, args2]); -}; - // Not implemented correctly exports.SameRealmTransfer = O => O; diff --git a/reference-implementation/lib/writable-stream.js b/reference-implementation/lib/writable-stream.js index 79b931e11..aed008338 100644 --- a/reference-implementation/lib/writable-stream.js +++ b/reference-implementation/lib/writable-stream.js @@ -1,7 +1,7 @@ 'use strict'; const assert = require('assert'); -const { InvokeOrNoop, PromiseInvokeOrNoop, PromiseInvokeOrFallbackOrNoop, ValidateAndNormalizeQueuingStrategy, - typeIsObject } = require('./helpers.js'); +const { InvokeOrNoop, PromiseInvokeOrNoop, ValidateAndNormalizeQueuingStrategy, typeIsObject } = + require('./helpers.js'); const { rethrowAssertionErrorRejection } = require('./utils.js'); const { DequeueValue, EnqueueValueWithSize, GetTotalQueueSize, PeekQueueValue } = require('./queue-with-sizes.js'); @@ -574,8 +574,7 @@ class WritableStreamDefaultController { function WritableStreamDefaultControllerAbort(controller, reason) { controller._queue = []; - const sinkAbortPromise = PromiseInvokeOrFallbackOrNoop(controller._underlyingSink, 'abort', [reason], - 'close', [controller]); + const sinkAbortPromise = PromiseInvokeOrNoop(controller._underlyingSink, 'abort', [reason]); return sinkAbortPromise.then(() => undefined); } diff --git a/reference-implementation/to-upstream-wpts/writable-streams/aborting.js b/reference-implementation/to-upstream-wpts/writable-streams/aborting.js index 87b25e72c..ee4eaeaef 100644 --- a/reference-implementation/to-upstream-wpts/writable-streams/aborting.js +++ b/reference-implementation/to-upstream-wpts/writable-streams/aborting.js @@ -250,15 +250,14 @@ promise_test(() => { }, 'Aborting a WritableStream after it is closed is a no-op'); promise_test(t => { + // Testing that per https://github.com/whatwg/streams/issues/620#issuecomment-263483953 the fallback to close was + // removed. + // Cannot use recordingWritableStream since it always has an abort - let controller; - let closeArgs; + let closeCalled = false; const ws = new WritableStream({ - start(c) { - controller = c; - }, - close(...args) { - closeArgs = args; + close() { + closeCalled = true; } }); @@ -267,9 +266,9 @@ promise_test(t => { writer.abort(); return promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with a TypeError').then(() => { - assert_array_equals(closeArgs, [controller], 'close must have been called, with the controller as its argument'); + assert_false(closeCalled, 'close must not have been called'); }); -}, 'WritableStream should call underlying sink\'s close if no abort is supplied'); +}, 'WritableStream should NOT call underlying sink\'s close if no abort is supplied (historical)'); promise_test(() => { let thenCalled = false; diff --git a/reference-implementation/to-upstream-wpts/writable-streams/general.js b/reference-implementation/to-upstream-wpts/writable-streams/general.js index 891b2520a..c284338a3 100644 --- a/reference-implementation/to-upstream-wpts/writable-streams/general.js +++ b/reference-implementation/to-upstream-wpts/writable-streams/general.js @@ -173,7 +173,9 @@ promise_test(t => { const writer2 = ws2.getWriter(); writer2.abort(); - // Test PromiseInvokeOrFallbackOrNoop. + // Test abort() with a close underlying sink method present. (Historical; see + // https://github.com/whatwg/streams/issues/620#issuecomment-263483953 for what used to be + // tested here. But more coverage can't hurt.) const ws3 = new WritableStream({ start: functionWithOverloads, write: functionWithOverloads,