@@ -115,6 +115,7 @@ const kHasFlowing = 1 << 23;
115
115
const kFlowing = 1 << 24 ;
116
116
const kHasPaused = 1 << 25 ;
117
117
const kPaused = 1 << 26 ;
118
+ const kDataListening = 1 << 27 ;
118
119
119
120
// TODO(benjamingr) it is likely slower to do it this way than with free functions
120
121
function makeBitMapDescriptor ( bit ) {
@@ -531,8 +532,7 @@ function canPushMore(state) {
531
532
}
532
533
533
534
function addChunk ( stream , state , chunk , addToFront ) {
534
- if ( ( state [ kState ] & ( kFlowing | kSync ) ) === kFlowing && state . length === 0 &&
535
- stream . listenerCount ( 'data' ) > 0 ) {
535
+ if ( ( state [ kState ] & ( kFlowing | kSync | kDataListening ) ) === ( kFlowing | kDataListening ) && state . length === 0 ) {
536
536
// Use the guard to avoid creating `Set()` repeatedly
537
537
// when we have multiple pipes.
538
538
if ( ( state [ kState ] & kMultiAwaitDrain ) !== 0 ) {
@@ -1058,7 +1058,7 @@ function pipeOnDrain(src, dest) {
1058
1058
}
1059
1059
1060
1060
if ( ( ! state . awaitDrainWriters || state . awaitDrainWriters . size === 0 ) &&
1061
- src . listenerCount ( 'data' ) ) {
1061
+ ( state [ kState ] & kDataListening ) !== 0 ) {
1062
1062
src . resume ( ) ;
1063
1063
}
1064
1064
} ;
@@ -1105,6 +1105,8 @@ Readable.prototype.on = function(ev, fn) {
1105
1105
const state = this . _readableState ;
1106
1106
1107
1107
if ( ev === 'data' ) {
1108
+ state [ kState ] |= kDataListening ;
1109
+
1108
1110
// Update readableListening so that resume() may be a no-op
1109
1111
// a few lines down. This is needed to support once('readable').
1110
1112
state . readableListening = this . listenerCount ( 'readable' ) > 0 ;
@@ -1131,6 +1133,8 @@ Readable.prototype.on = function(ev, fn) {
1131
1133
Readable . prototype . addListener = Readable . prototype . on ;
1132
1134
1133
1135
Readable . prototype . removeListener = function ( ev , fn ) {
1136
+ const state = this . _readableState ;
1137
+
1134
1138
const res = Stream . prototype . removeListener . call ( this ,
1135
1139
ev , fn ) ;
1136
1140
@@ -1142,6 +1146,8 @@ Readable.prototype.removeListener = function(ev, fn) {
1142
1146
// resume within the same tick will have no
1143
1147
// effect.
1144
1148
process . nextTick ( updateReadableListening , this ) ;
1149
+ } else if ( ev === 'data' && this . listenerCount ( 'data' ) === 0 ) {
1150
+ state [ kState ] &= ~ kDataListening ;
1145
1151
}
1146
1152
1147
1153
return res ;
@@ -1175,7 +1181,7 @@ function updateReadableListening(self) {
1175
1181
state [ kState ] |= kHasFlowing | kFlowing ;
1176
1182
1177
1183
// Crude way to check if we should resume.
1178
- } else if ( self . listenerCount ( 'data' ) > 0 ) {
1184
+ } else if ( ( state [ kState ] & kDataListening ) !== 0 ) {
1179
1185
self . resume ( ) ;
1180
1186
} else if ( ( state [ kState ] & kReadableListening ) === 0 ) {
1181
1187
state [ kState ] &= ~ ( kHasFlowing | kFlowing ) ;
0 commit comments