@@ -1595,6 +1595,13 @@ function readableStreamPipeTo(
15951595 // tells us that the promise must be rejected even
15961596 // when error is undefine.
15971597 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 ;
15981605 writableStreamDefaultWriterRelease ( writer ) ;
15991606 readableStreamReaderGenericRelease ( reader ) ;
16001607 if ( signal !== undefined )
@@ -1692,12 +1699,6 @@ function readableStreamPipeTo(
16921699 PromisePrototypeThen ( promise , undefined , action ) ;
16931700 }
16941701
1695- function watchClosed ( stream , promise , action ) {
1696- if ( stream [ kState ] . state === 'closed' )
1697- action ( ) ;
1698- else
1699- PromisePrototypeThen ( promise , action , ( ) => { } ) ;
1700- }
17011702
17021703 // The pump loop is callback-driven to avoid per-iteration promise
17031704 // allocations. At most one read is in flight at a time, so one read
@@ -1828,15 +1829,34 @@ function readableStreamPipeTo(
18281829
18291830 pump ( ) ;
18301831
1831- watchErrored ( source , readerClosedPromise ( reader ) . promise , ( error ) => {
1832+ function onSourceErrored ( error ) {
18321833 if ( ! preventAbort ) {
18331834 return shutdownWithAnAction (
18341835 ( ) => writableStreamAbort ( dest , error ) ,
18351836 true ,
18361837 error ) ;
18371838 }
18381839 shutdown ( true , error ) ;
1839- } ) ;
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+ }
18401860
18411861 watchErrored ( dest , writerClosedPromise ( writer ) . promise , ( error ) => {
18421862 if ( ! preventCancel ) {
@@ -1848,13 +1868,8 @@ function readableStreamPipeTo(
18481868 shutdown ( true , error ) ;
18491869 } ) ;
18501870
1851- watchClosed ( source , readerClosedPromise ( reader ) . promise , ( ) => {
1852- if ( ! preventClose ) {
1853- return shutdownWithAnAction (
1854- ( ) => writableStreamDefaultWriterCloseWithErrorPropagation ( writer ) ) ;
1855- }
1856- shutdown ( ) ;
1857- } ) ;
1871+ if ( source [ kState ] . state === 'closed' )
1872+ onSourceClosed ( ) ;
18581873
18591874 if ( writableStreamCloseQueuedOrInFlight ( dest ) ||
18601875 dest [ kState ] . state === 'closed' ) {
@@ -2864,29 +2879,27 @@ function setupReadableStreamDefaultController(
28642879
28652880 const startResult = startAlgorithm ( ) ;
28662881
2882+ const started = ( ) => {
2883+ controller [ kState ] . started = true ;
2884+ assert ( ! controller [ kState ] . pulling ) ;
2885+ assert ( ! controller [ kState ] . pullAgain ) ;
2886+ readableStreamDefaultControllerCallPullIfNeeded ( controller ) ;
2887+ } ;
2888+
28672889 if ( startResult === null ||
28682890 ( typeof startResult !== 'object' && typeof startResult !== 'function' ) ) {
28692891 // Non-thenable start result: fulfillment is guaranteed and no .then
2870- // lookup on the result is observable, so run the post-start step
2871- // directly at the exact microtask position the promise reaction
2872- // would have had, skipping two promise allocations.
2873- queueMicrotask ( ( ) => {
2874- controller [ kState ] . started = true ;
2875- assert ( ! controller [ kState ] . pulling ) ;
2876- assert ( ! controller [ kState ] . pullAgain ) ;
2877- readableStreamDefaultControllerCallPullIfNeeded ( controller ) ;
2878- } ) ;
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 ) ;
28792895 return ;
28802896 }
28812897
2898+ // The wrapper promise matches the reference implementation's
2899+ // promiseResolvedWith(), whose extra microtask hops WPT relies on.
28822900 PromisePrototypeThen (
28832901 new Promise ( ( r ) => r ( startResult ) ) ,
2884- ( ) => {
2885- controller [ kState ] . started = true ;
2886- assert ( ! controller [ kState ] . pulling ) ;
2887- assert ( ! controller [ kState ] . pullAgain ) ;
2888- readableStreamDefaultControllerCallPullIfNeeded ( controller ) ;
2889- } ,
2902+ started ,
28902903 ( error ) => readableStreamDefaultControllerError ( controller , error ) ) ;
28912904}
28922905
@@ -3748,26 +3761,23 @@ function setupReadableByteStreamController(
37483761
37493762 const startResult = startAlgorithm ( ) ;
37503763
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.
37513772 if ( startResult === null ||
37523773 ( typeof startResult !== 'object' && typeof startResult !== 'function' ) ) {
3753- // See setupReadableStreamDefaultController.
3754- queueMicrotask ( ( ) => {
3755- controller [ kState ] . started = true ;
3756- assert ( ! controller [ kState ] . pulling ) ;
3757- assert ( ! controller [ kState ] . pullAgain ) ;
3758- readableByteStreamControllerCallPullIfNeeded ( controller ) ;
3759- } ) ;
3774+ queueMicrotask ( started ) ;
37603775 return ;
37613776 }
37623777
37633778 PromisePrototypeThen (
37643779 new Promise ( ( r ) => r ( startResult ) ) ,
3765- ( ) => {
3766- controller [ kState ] . started = true ;
3767- assert ( ! controller [ kState ] . pulling ) ;
3768- assert ( ! controller [ kState ] . pullAgain ) ;
3769- readableByteStreamControllerCallPullIfNeeded ( controller ) ;
3770- } ,
3780+ started ,
37713781 ( error ) => readableByteStreamControllerError ( controller , error ) ) ;
37723782}
37733783
0 commit comments