@@ -253,6 +253,13 @@ class ReadableStream {
253253 */
254254 constructor ( source = kEmptyObject , strategy = kEmptyObject ) {
255255 markTransferMode ( this , false , true ) ;
256+ // Internal construction (tee, transform streams, adapters, transfer):
257+ // the caller sets up the controller, so every ReadableStream shares
258+ // one hidden class and no per-instance prototype swap is needed.
259+ if ( source === kSkipThrow ) {
260+ this [ kState ] = createReadableStreamState ( ) ;
261+ return ;
262+ }
256263 validateObject ( source , 'source' , kValidateObjectAllowObjects ) ;
257264 validateObject ( strategy , 'strategy' , kValidateObjectAllowObjectsAndNull ) ;
258265 this [ kState ] = createReadableStreamState ( ) ;
@@ -718,22 +725,8 @@ ObjectDefineProperties(ReadableStream, {
718725 from : kEnumerableProperty ,
719726} ) ;
720727
721- function InternalTransferredReadableStream ( ) {
722- ObjectSetPrototypeOf ( this , ReadableStream . prototype ) ;
723- markTransferMode ( this , false , true ) ;
724- this [ kType ] = 'ReadableStream' ;
725- this [ kState ] = createReadableStreamState ( ) ;
726- }
727-
728- ObjectSetPrototypeOf ( InternalTransferredReadableStream . prototype , ReadableStream . prototype ) ;
729- ObjectSetPrototypeOf ( InternalTransferredReadableStream , ReadableStream ) ;
730-
731728function TransferredReadableStream ( ) {
732- const stream = new InternalTransferredReadableStream ( ) ;
733-
734- stream . constructor = ReadableStream ;
735-
736- return stream ;
729+ return new ReadableStream ( kSkipThrow ) ;
737730}
738731
739732TransferredReadableStream . prototype [ kDeserialize ] = ( ) => { } ;
@@ -1350,57 +1343,29 @@ ObjectDefineProperties(ReadableByteStreamController.prototype, {
13501343 [ SymbolToStringTag ] : getNonWritablePropertyDescriptor ( ReadableByteStreamController . name ) ,
13511344} ) ;
13521345
1353- function InternalReadableStream ( start , pull , cancel , highWaterMark , size ) {
1354- ObjectSetPrototypeOf ( this , ReadableStream . prototype ) ;
1355- markTransferMode ( this , false , true ) ;
1356- this [ kType ] = 'ReadableStream' ;
1357- this [ kState ] = createReadableStreamState ( ) ;
1358- const controller = new ReadableStreamDefaultController ( kSkipThrow ) ;
1346+ function createReadableStream ( start , pull , cancel , highWaterMark = 1 , size = defaultSizeAlgorithm ) {
1347+ const stream = new ReadableStream ( kSkipThrow ) ;
13591348 setupReadableStreamDefaultController (
1360- this ,
1361- controller ,
1349+ stream ,
1350+ new ReadableStreamDefaultController ( kSkipThrow ) ,
13621351 start ,
13631352 pull ,
13641353 cancel ,
13651354 highWaterMark ,
13661355 size ) ;
1367- }
1368-
1369- ObjectSetPrototypeOf ( InternalReadableStream . prototype , ReadableStream . prototype ) ;
1370- ObjectSetPrototypeOf ( InternalReadableStream , ReadableStream ) ;
1371-
1372- function createReadableStream ( start , pull , cancel , highWaterMark = 1 , size = defaultSizeAlgorithm ) {
1373- const stream = new InternalReadableStream ( start , pull , cancel , highWaterMark , size ) ;
1374-
1375- // For spec compliance the InternalReadableStream must be a ReadableStream
1376- stream . constructor = ReadableStream ;
13771356 return stream ;
13781357}
13791358
1380- function InternalReadableByteStream ( start , pull , cancel ) {
1381- ObjectSetPrototypeOf ( this , ReadableStream . prototype ) ;
1382- markTransferMode ( this , false , true ) ;
1383- this [ kType ] = 'ReadableStream' ;
1384- this [ kState ] = createReadableStreamState ( ) ;
1385- const controller = new ReadableByteStreamController ( kSkipThrow ) ;
1359+ function createReadableByteStream ( start , pull , cancel ) {
1360+ const stream = new ReadableStream ( kSkipThrow ) ;
13861361 setupReadableByteStreamController (
1387- this ,
1388- controller ,
1362+ stream ,
1363+ new ReadableByteStreamController ( kSkipThrow ) ,
13891364 start ,
13901365 pull ,
13911366 cancel ,
13921367 0 ,
13931368 undefined ) ;
1394- }
1395-
1396- ObjectSetPrototypeOf ( InternalReadableByteStream . prototype , ReadableStream . prototype ) ;
1397- ObjectSetPrototypeOf ( InternalReadableByteStream , ReadableStream ) ;
1398-
1399- function createReadableByteStream ( start , pull , cancel ) {
1400- const stream = new InternalReadableByteStream ( start , pull , cancel ) ;
1401-
1402- // For spec compliance the InternalReadableByteStream must be a ReadableStream
1403- stream . constructor = ReadableStream ;
14041369 return stream ;
14051370}
14061371
@@ -1630,6 +1595,13 @@ function readableStreamPipeTo(
16301595 // tells us that the promise must be rejected even
16311596 // when error is undefine.
16321597 function finalize ( rejected , error ) {
1598+ // The pipe is the only observer of the reader's and writer's promise
1599+ // records (including the ready hook installed by parkOnReady), and
1600+ // it is done with them: dropping them lets release skip the
1601+ // pending-promise probes and the rejections nothing would handle.
1602+ writer [ kState ] . ready = undefined ;
1603+ writer [ kState ] . close = undefined ;
1604+ reader [ kState ] . close = undefined ;
16331605 writableStreamDefaultWriterRelease ( writer ) ;
16341606 readableStreamReaderGenericRelease ( reader ) ;
16351607 if ( signal !== undefined )
@@ -1727,12 +1699,6 @@ function readableStreamPipeTo(
17271699 PromisePrototypeThen ( promise , undefined , action ) ;
17281700 }
17291701
1730- function watchClosed ( stream , promise , action ) {
1731- if ( stream [ kState ] . state === 'closed' )
1732- action ( ) ;
1733- else
1734- PromisePrototypeThen ( promise , action , ( ) => { } ) ;
1735- }
17361702
17371703 // The pump loop is callback-driven to avoid per-iteration promise
17381704 // allocations. At most one read is in flight at a time, so one read
@@ -1863,15 +1829,34 @@ function readableStreamPipeTo(
18631829
18641830 pump ( ) ;
18651831
1866- watchErrored ( source , readerClosedPromise ( reader ) . promise , ( error ) => {
1832+ function onSourceErrored ( error ) {
18671833 if ( ! preventAbort ) {
18681834 return shutdownWithAnAction (
18691835 ( ) => writableStreamAbort ( dest , error ) ,
18701836 true ,
18711837 error ) ;
18721838 }
18731839 shutdown ( true , error ) ;
1874- } ) ;
1840+ }
1841+
1842+ function onSourceClosed ( ) {
1843+ if ( ! preventClose ) {
1844+ return shutdownWithAnAction (
1845+ ( ) => writableStreamDefaultWriterCloseWithErrorPropagation ( writer ) ) ;
1846+ }
1847+ shutdown ( ) ;
1848+ }
1849+
1850+ // The spec installs the source-errored watcher before the dest-errored
1851+ // one and the source-closed watcher last; a source that is already
1852+ // errored is handled before the dest watcher is installed, and an
1853+ // already-closed source after it, as before.
1854+ if ( source [ kState ] . state === 'errored' ) {
1855+ onSourceErrored ( source [ kState ] . storedError ) ;
1856+ } else if ( source [ kState ] . state !== 'closed' ) {
1857+ PromisePrototypeThen (
1858+ readerClosedPromise ( reader ) . promise , onSourceClosed , onSourceErrored ) ;
1859+ }
18751860
18761861 watchErrored ( dest , writerClosedPromise ( writer ) . promise , ( error ) => {
18771862 if ( ! preventCancel ) {
@@ -1883,13 +1868,8 @@ function readableStreamPipeTo(
18831868 shutdown ( true , error ) ;
18841869 } ) ;
18851870
1886- watchClosed ( source , readerClosedPromise ( reader ) . promise , ( ) => {
1887- if ( ! preventClose ) {
1888- return shutdownWithAnAction (
1889- ( ) => writableStreamDefaultWriterCloseWithErrorPropagation ( writer ) ) ;
1890- }
1891- shutdown ( ) ;
1892- } ) ;
1871+ if ( source [ kState ] . state === 'closed' )
1872+ onSourceClosed ( ) ;
18931873
18941874 if ( writableStreamCloseQueuedOrInFlight ( dest ) ||
18951875 dest [ kState ] . state === 'closed' ) {
@@ -2899,29 +2879,27 @@ function setupReadableStreamDefaultController(
28992879
29002880 const startResult = startAlgorithm ( ) ;
29012881
2882+ const started = ( ) => {
2883+ controller [ kState ] . started = true ;
2884+ assert ( ! controller [ kState ] . pulling ) ;
2885+ assert ( ! controller [ kState ] . pullAgain ) ;
2886+ readableStreamDefaultControllerCallPullIfNeeded ( controller ) ;
2887+ } ;
2888+
29022889 if ( startResult === null ||
29032890 ( typeof startResult !== 'object' && typeof startResult !== 'function' ) ) {
29042891 // Non-thenable start result: fulfillment is guaranteed and no .then
2905- // lookup on the result is observable, so run the post-start step
2906- // directly at the exact microtask position the promise reaction
2907- // would have had, skipping two promise allocations.
2908- queueMicrotask ( ( ) => {
2909- controller [ kState ] . started = true ;
2910- assert ( ! controller [ kState ] . pulling ) ;
2911- assert ( ! controller [ kState ] . pullAgain ) ;
2912- readableStreamDefaultControllerCallPullIfNeeded ( controller ) ;
2913- } ) ;
2892+ // lookup on the result is observable, so the post-start step runs at
2893+ // the exact microtask position the promise reaction would have had.
2894+ queueMicrotask ( started ) ;
29142895 return ;
29152896 }
29162897
2898+ // The wrapper promise matches the reference implementation's
2899+ // promiseResolvedWith(), whose extra microtask hops WPT relies on.
29172900 PromisePrototypeThen (
29182901 new Promise ( ( r ) => r ( startResult ) ) ,
2919- ( ) => {
2920- controller [ kState ] . started = true ;
2921- assert ( ! controller [ kState ] . pulling ) ;
2922- assert ( ! controller [ kState ] . pullAgain ) ;
2923- readableStreamDefaultControllerCallPullIfNeeded ( controller ) ;
2924- } ,
2902+ started ,
29252903 ( error ) => readableStreamDefaultControllerError ( controller , error ) ) ;
29262904}
29272905
@@ -3783,26 +3761,23 @@ function setupReadableByteStreamController(
37833761
37843762 const startResult = startAlgorithm ( ) ;
37853763
3764+ const started = ( ) => {
3765+ controller [ kState ] . started = true ;
3766+ assert ( ! controller [ kState ] . pulling ) ;
3767+ assert ( ! controller [ kState ] . pullAgain ) ;
3768+ readableByteStreamControllerCallPullIfNeeded ( controller ) ;
3769+ } ;
3770+
3771+ // See setupReadableStreamDefaultController.
37863772 if ( startResult === null ||
37873773 ( typeof startResult !== 'object' && typeof startResult !== 'function' ) ) {
3788- // See setupReadableStreamDefaultController.
3789- queueMicrotask ( ( ) => {
3790- controller [ kState ] . started = true ;
3791- assert ( ! controller [ kState ] . pulling ) ;
3792- assert ( ! controller [ kState ] . pullAgain ) ;
3793- readableByteStreamControllerCallPullIfNeeded ( controller ) ;
3794- } ) ;
3774+ queueMicrotask ( started ) ;
37953775 return ;
37963776 }
37973777
37983778 PromisePrototypeThen (
37993779 new Promise ( ( r ) => r ( startResult ) ) ,
3800- ( ) => {
3801- controller [ kState ] . started = true ;
3802- assert ( ! controller [ kState ] . pulling ) ;
3803- assert ( ! controller [ kState ] . pullAgain ) ;
3804- readableByteStreamControllerCallPullIfNeeded ( controller ) ;
3805- } ,
3780+ started ,
38063781 ( error ) => readableByteStreamControllerError ( controller , error ) ) ;
38073782}
38083783
0 commit comments