@@ -134,8 +134,10 @@ function ReadableState(options, stream, isDuplex) {
134134 // Everything else in the universe uses 'utf8', though.
135135 this . defaultEncoding = options . defaultEncoding || 'utf8' ;
136136
137- // The number of writers that are awaiting a drain event in .pipe()s
138- this . awaitDrain = 0 ;
137+ // Ref the piped dest which we need a drain event on it
138+ // type: null | Writable | Set<Writable>
139+ this . awaitDrainWriters = null ;
140+ this . multiAwaitDrain = false ;
139141
140142 // If true, a maybeReadMore has been scheduled
141143 this . readingMore = false ;
@@ -310,7 +312,13 @@ function readableAddChunk(stream, chunk, encoding, addToFront) {
310312
311313function addChunk ( stream , state , chunk , addToFront ) {
312314 if ( state . flowing && state . length === 0 && ! state . sync ) {
313- state . awaitDrain = 0 ;
315+ // Use the guard to avoid creating `Set()` repeatedly
316+ // when we have multiple pipes.
317+ if ( state . multiAwaitDrain ) {
318+ state . awaitDrainWriters . clear ( ) ;
319+ } else {
320+ state . awaitDrainWriters = null ;
321+ }
314322 stream . emit ( 'data' , chunk ) ;
315323 } else {
316324 // Update the buffer info.
@@ -511,7 +519,11 @@ Readable.prototype.read = function(n) {
511519 n = 0 ;
512520 } else {
513521 state . length -= n ;
514- state . awaitDrain = 0 ;
522+ if ( state . multiAwaitDrain ) {
523+ state . awaitDrainWriters . clear ( ) ;
524+ } else {
525+ state . awaitDrainWriters = null ;
526+ }
515527 }
516528
517529 if ( state . length === 0 ) {
@@ -656,6 +668,15 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
656668 const src = this ;
657669 const state = this . _readableState ;
658670
671+ if ( state . pipes . length === 1 ) {
672+ if ( ! state . multiAwaitDrain ) {
673+ state . multiAwaitDrain = true ;
674+ state . awaitDrainWriters = new Set (
675+ state . awaitDrainWriters ? [ state . awaitDrainWriters ] : [ ]
676+ ) ;
677+ }
678+ }
679+
659680 state . pipes . push ( dest ) ;
660681 debug ( 'pipe count=%d opts=%j' , state . pipes . length , pipeOpts ) ;
661682
@@ -709,7 +730,7 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
709730 // flowing again.
710731 // So, if this is awaiting a drain, then we just call it now.
711732 // If we don't know, then assume that we are waiting for one.
712- if ( ondrain && state . awaitDrain &&
733+ if ( ondrain && state . awaitDrainWriters &&
713734 ( ! dest . _writableState || dest . _writableState . needDrain ) )
714735 ondrain ( ) ;
715736 }
@@ -724,16 +745,22 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
724745 // to get stuck in a permanently paused state if that write
725746 // also returned false.
726747 // => Check whether `dest` is still a piping destination.
727- if ( state . pipes . length > 0 && state . pipes . includes ( dest ) && ! cleanedUp ) {
728- debug ( 'false write response, pause' , state . awaitDrain ) ;
729- state . awaitDrain ++ ;
748+ if ( ! cleanedUp ) {
749+ if ( state . pipes . length === 1 && state . pipes [ 0 ] === dest ) {
750+ debug ( 'false write response, pause' , 0 ) ;
751+ state . awaitDrainWriters = dest ;
752+ state . multiAwaitDrain = false ;
753+ } else if ( state . pipes . length > 1 && state . pipes . includes ( dest ) ) {
754+ debug ( 'false write response, pause' , state . awaitDrainWriters . size ) ;
755+ state . awaitDrainWriters . add ( dest ) ;
756+ }
730757 }
731758 if ( ! ondrain ) {
732759 // When the dest drains, it reduces the awaitDrain counter
733760 // on the source. This would be more elegant with a .once()
734761 // handler in flow(), but adding and removing repeatedly is
735762 // too slow.
736- ondrain = pipeOnDrain ( src ) ;
763+ ondrain = pipeOnDrain ( src , dest ) ;
737764 dest . on ( 'drain' , ondrain ) ;
738765 }
739766 src . pause ( ) ;
@@ -783,13 +810,23 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
783810 return dest ;
784811} ;
785812
786- function pipeOnDrain ( src ) {
813+ function pipeOnDrain ( src , dest ) {
787814 return function pipeOnDrainFunctionResult ( ) {
788815 const state = src . _readableState ;
789- debug ( 'pipeOnDrain' , state . awaitDrain ) ;
790- if ( state . awaitDrain )
791- state . awaitDrain -- ;
792- if ( state . awaitDrain === 0 && EE . listenerCount ( src , 'data' ) ) {
816+
817+ // `ondrain` will call directly,
818+ // `this` maybe not a reference to dest,
819+ // so we use the real dest here.
820+ if ( state . awaitDrainWriters === dest ) {
821+ debug ( 'pipeOnDrain' , 1 ) ;
822+ state . awaitDrainWriters = null ;
823+ } else if ( state . multiAwaitDrain ) {
824+ debug ( 'pipeOnDrain' , state . awaitDrainWriters . size ) ;
825+ state . awaitDrainWriters . delete ( dest ) ;
826+ }
827+
828+ if ( ( ! state . awaitDrainWriters || state . awaitDrainWriters . size === 0 ) &&
829+ EE . listenerCount ( src , 'data' ) ) {
793830 state . flowing = true ;
794831 flow ( src ) ;
795832 }
0 commit comments