@@ -27,6 +27,7 @@ const {
27
27
NumberIsNaN,
28
28
ObjectDefineProperties,
29
29
ObjectSetPrototypeOf,
30
+ Set,
30
31
SymbolAsyncIterator,
31
32
Symbol
32
33
} = primordials ;
@@ -146,8 +147,10 @@ function ReadableState(options, stream, isDuplex) {
146
147
// Everything else in the universe uses 'utf8', though.
147
148
this . defaultEncoding = ( options && options . defaultEncoding ) || 'utf8' ;
148
149
149
- // The number of writers that are awaiting a drain event in .pipe()s
150
- this . awaitDrain = 0 ;
150
+ // Ref the piped dest which we need a drain event on it
151
+ // type: null | Writable | Set<Writable>
152
+ this . awaitDrainWriters = null ;
153
+ this . multiAwaitDrain = false ;
151
154
152
155
// If true, a maybeReadMore has been scheduled
153
156
this . readingMore = false ;
@@ -282,7 +285,13 @@ function readableAddChunk(stream, chunk, encoding, addToFront) {
282
285
283
286
function addChunk ( stream , state , chunk , addToFront ) {
284
287
if ( state . flowing && state . length === 0 && ! state . sync ) {
285
- state . awaitDrain = 0 ;
288
+ // Use the guard to avoid creating `Set()` repeatedly
289
+ // when we have multiple pipes.
290
+ if ( state . multiAwaitDrain ) {
291
+ state . awaitDrainWriters . clear ( ) ;
292
+ } else {
293
+ state . awaitDrainWriters = null ;
294
+ }
286
295
stream . emit ( 'data' , chunk ) ;
287
296
} else {
288
297
// Update the buffer info.
@@ -475,7 +484,11 @@ Readable.prototype.read = function(n) {
475
484
n = 0 ;
476
485
} else {
477
486
state . length -= n ;
478
- state . awaitDrain = 0 ;
487
+ if ( state . multiAwaitDrain ) {
488
+ state . awaitDrainWriters . clear ( ) ;
489
+ } else {
490
+ state . awaitDrainWriters = null ;
491
+ }
479
492
}
480
493
481
494
if ( state . length === 0 ) {
@@ -620,6 +633,15 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
620
633
const src = this ;
621
634
const state = this . _readableState ;
622
635
636
+ if ( state . pipesCount === 1 ) {
637
+ if ( ! state . multiAwaitDrain ) {
638
+ state . multiAwaitDrain = true ;
639
+ state . awaitDrainWriters = new Set (
640
+ state . awaitDrainWriters ? [ state . awaitDrainWriters ] : [ ]
641
+ ) ;
642
+ }
643
+ }
644
+
623
645
switch ( state . pipesCount ) {
624
646
case 0 :
625
647
state . pipes = dest ;
@@ -684,7 +706,7 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
684
706
// flowing again.
685
707
// So, if this is awaiting a drain, then we just call it now.
686
708
// If we don't know, then assume that we are waiting for one.
687
- if ( ondrain && state . awaitDrain &&
709
+ if ( ondrain && state . awaitDrainWriters &&
688
710
( ! dest . _writableState || dest . _writableState . needDrain ) )
689
711
ondrain ( ) ;
690
712
}
@@ -699,21 +721,23 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
699
721
// to get stuck in a permanently paused state if that write
700
722
// also returned false.
701
723
// => Check whether `dest` is still a piping destination.
702
- if ( ( ( state . pipesCount === 1 && state . pipes === dest ) ||
703
- ( state . pipesCount > 1 && state . pipes . includes ( dest ) ) ) &&
704
- ! cleanedUp ) {
705
- debug ( 'false write response, pause' , state . awaitDrain ) ;
706
- state . awaitDrain ++ ;
707
- }
708
724
if ( ! cleanedUp ) {
725
+ if ( state . pipesCount === 1 && state . pipes === dest ) {
726
+ debug ( 'false write response, pause' , 0 ) ;
727
+ state . awaitDrainWriters = dest ;
728
+ state . multiAwaitDrain = false ;
729
+ } else if ( state . pipesCount > 1 && state . pipes . includes ( dest ) ) {
730
+ debug ( 'false write response, pause' , state . awaitDrainWriters . size ) ;
731
+ state . awaitDrainWriters . add ( dest ) ;
732
+ }
709
733
src . pause ( ) ;
710
734
}
711
735
if ( ! ondrain ) {
712
736
// When the dest drains, it reduces the awaitDrain counter
713
737
// on the source. This would be more elegant with a .once()
714
738
// handler in flow(), but adding and removing repeatedly is
715
739
// too slow.
716
- ondrain = pipeOnDrain ( src ) ;
740
+ ondrain = pipeOnDrain ( src , dest ) ;
717
741
dest . on ( 'drain' , ondrain ) ;
718
742
}
719
743
}
@@ -762,13 +786,23 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
762
786
return dest ;
763
787
} ;
764
788
765
- function pipeOnDrain ( src ) {
789
+ function pipeOnDrain ( src , dest ) {
766
790
return function pipeOnDrainFunctionResult ( ) {
767
791
const state = src . _readableState ;
768
- debug ( 'pipeOnDrain' , state . awaitDrain ) ;
769
- if ( state . awaitDrain )
770
- state . awaitDrain -- ;
771
- if ( state . awaitDrain === 0 && EE . listenerCount ( src , 'data' ) ) {
792
+
793
+ // `ondrain` will call directly,
794
+ // `this` maybe not a reference to dest,
795
+ // so we use the real dest here.
796
+ if ( state . awaitDrainWriters === dest ) {
797
+ debug ( 'pipeOnDrain' , 1 ) ;
798
+ state . awaitDrainWriters = null ;
799
+ } else if ( state . multiAwaitDrain ) {
800
+ debug ( 'pipeOnDrain' , state . awaitDrainWriters . size ) ;
801
+ state . awaitDrainWriters . delete ( dest ) ;
802
+ }
803
+
804
+ if ( ( ! state . awaitDrainWriters || state . awaitDrainWriters . size === 0 ) &&
805
+ EE . listenerCount ( src , 'data' ) ) {
772
806
state . flowing = true ;
773
807
flow ( src ) ;
774
808
}
0 commit comments