diff --git a/index.bs b/index.bs index 730af3731..458a09f59 100644 --- a/index.bs +++ b/index.bs @@ -1322,8 +1322,8 @@ the following [=struct/items=]: : chunk steps :: An algorithm taking a [=chunk=], called when a chunk is available for reading : close steps -:: An algorithm taking a [=chunk=], called when no chunks are available because the stream is - closed +:: An algorithm taking a [=chunk=] or undefined, called when no chunks are available because + the stream is closed : error steps :: An algorithm taking a JavaScript value, called when no [=chunks=] are available because the stream is errored @@ -1331,8 +1331,10 @@ the following [=struct/items=]:

The [=read-into request/close steps=] take a [=chunk=] so that it can return the backing memory to the caller if possible. For example, {{ReadableStreamBYOBReader/read()|byobReader.read(chunk)}} will fulfill with { -value: newViewOnSameMemory, done: true } for closed streams, instead of the more traditional -{ value: undefined, done: true }. +value: newViewOnSameMemory, done: true } for closed streams. If the stream is +[=cancel a readable stream|canceled=], the backing memory is discarded and +{{ReadableStreamBYOBReader/read()|byobReader.read(chunk)}} fulfills with the more traditional +{ value: undefined, done: true } instead.

Constructor, methods, and properties

@@ -1369,6 +1371,10 @@ value: newViewOnSameMemory, done: true } for closed streams, instead of t the same type) onto the same backing memory region, with no modifications, to ensure the memory is returned to the caller. +
  • If the reader is [=cancel a readable stream|canceled=], the promise will be fulfilled with + an object of the form { value: undefined, done: true }. In this case, + the backing memory region of |view| is discarded and not returned to the caller. +
  • If the stream becomes errored, the promise will be rejected with the relevant error. @@ -1849,10 +1855,7 @@ counterparts for default controllers, as discussed in [[#rs-abstract-ops-used-by id="rbs-controller-private-cancel">\[[CancelSteps]](|reason|) implements the [$ReadableStreamController/[[CancelSteps]]$] contract. It performs the following steps: - 1. If [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=] is not [=list/is - empty|empty=], - 1. Let |firstDescriptor| be [=this=].[=ReadableByteStreamController/[[pendingPullIntos]]=][0]. - 1. Set |firstDescriptor|'s [=pull-into descriptor/bytes filled=] to 0. + 1. Perform ! [$ReadableByteStreamControllerClearPendingPullIntos$]([=this=]). 1. Perform ! [$ResetQueue$]([=this=]). 1. Let |result| be the result of performing [=this=].[=ReadableByteStreamController/[[cancelAlgorithm]]=], passing in |reason|. @@ -2361,6 +2364,11 @@ the {{ReadableStream}}'s public API. 1. If |stream|.[=ReadableStream/[[state]]=] is "`errored`", return [=a promise rejected with=] |stream|.[=ReadableStream/[[storedError]]=]. 1. Perform ! [$ReadableStreamClose$](|stream|). + 1. Let |reader| be |stream|.[=ReadableStream/[[reader]]=]. + 1. If |reader| is not undefined and |reader| [=implements=] {{ReadableStreamBYOBReader}}, + 1. [=list/For each=] |readIntoRequest| of |reader|.[=ReadableStreamBYOBReader/[[readIntoRequests]]=], + 1. Perform |readIntoRequest|'s [=read-into request/close steps=], given undefined. + 1. Set |reader|.[=ReadableStreamBYOBReader/[[readIntoRequests]]=] to an empty [=list=]. 1. Let |sourceCancelPromise| be ! |stream|.[=ReadableStream/[[controller]]=].[$ReadableStreamController/[[CancelSteps]]$](|reason|). 1. Return the result of [=reacting=] to |sourceCancelPromise| with a fulfillment step that returns diff --git a/reference-implementation/lib/ReadableByteStreamController-impl.js b/reference-implementation/lib/ReadableByteStreamController-impl.js index 799ea3799..c0ab7182a 100644 --- a/reference-implementation/lib/ReadableByteStreamController-impl.js +++ b/reference-implementation/lib/ReadableByteStreamController-impl.js @@ -66,10 +66,7 @@ exports.implementation = class ReadableByteStreamControllerImpl { } [CancelSteps](reason) { - if (this._pendingPullIntos.length > 0) { - const firstDescriptor = this._pendingPullIntos[0]; - firstDescriptor.bytesFilled = 0; - } + aos.ReadableByteStreamControllerClearPendingPullIntos(this); ResetQueue(this); diff --git a/reference-implementation/lib/abstract-ops/readable-streams.js b/reference-implementation/lib/abstract-ops/readable-streams.js index 988519581..e8aa76ad5 100644 --- a/reference-implementation/lib/abstract-ops/readable-streams.js +++ b/reference-implementation/lib/abstract-ops/readable-streams.js @@ -28,6 +28,7 @@ Object.assign(exports, { IsReadableStreamLocked, ReadableByteStreamControllerCallPullIfNeeded, ReadableByteStreamControllerClearAlgorithms, + ReadableByteStreamControllerClearPendingPullIntos, ReadableByteStreamControllerClose, ReadableByteStreamControllerEnqueue, ReadableByteStreamControllerError, @@ -453,6 +454,14 @@ function ReadableStreamCancel(stream, reason) { ReadableStreamClose(stream); + const reader = stream._reader; + if (reader !== undefined && ReadableStreamBYOBReader.isImpl(reader)) { + for (const readIntoRequest of reader._readIntoRequests) { + readIntoRequest.closeSteps(undefined); + } + reader._readIntoRequests = []; + } + const sourceCancelPromise = stream._controller[CancelSteps](reason); return transformPromiseWith(sourceCancelPromise, () => undefined); } diff --git a/reference-implementation/web-platform-tests b/reference-implementation/web-platform-tests index 7b29ee36c..b869e60df 160000 --- a/reference-implementation/web-platform-tests +++ b/reference-implementation/web-platform-tests @@ -1 +1 @@ -Subproject commit 7b29ee36cc22bdad06b4f98df73358ca959fe0a7 +Subproject commit b869e60df1b8d3840e09b41c5e987c7e23f6856c