Skip to content

Commit bca23b9

Browse files
ronagBridgeAR
authored andcommitted
stream: reset flowing state if no 'readable' or 'data' listeners
If we don't have any 'readable' or 'data' listeners and we are not about to resume. Then reset flowing state to initial null state. PR-URL: #31036 Fixes: #24474 Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Rich Trott <[email protected]>
1 parent 1463214 commit bca23b9

File tree

3 files changed

+58
-5
lines changed

3 files changed

+58
-5
lines changed

lib/_stream_readable.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const {
2828
ObjectDefineProperty,
2929
ObjectSetPrototypeOf,
3030
SymbolAsyncIterator,
31+
Symbol
3132
} = primordials;
3233

3334
module.exports = Readable;
@@ -51,6 +52,8 @@ const {
5152
ERR_STREAM_UNSHIFT_AFTER_END_EVENT
5253
} = require('internal/errors').codes;
5354

55+
const kPaused = Symbol('kPaused');
56+
5457
// Lazy loaded to improve the startup performance.
5558
let StringDecoder;
5659
let createReadableStreamAsyncIterator;
@@ -126,7 +129,7 @@ function ReadableState(options, stream, isDuplex) {
126129
this.emittedReadable = false;
127130
this.readableListening = false;
128131
this.resumeScheduled = false;
129-
this.paused = true;
132+
this[kPaused] = null;
130133

131134
// True if the error was already emitted and should not be thrown again
132135
this.errorEmitted = false;
@@ -170,6 +173,16 @@ ObjectDefineProperty(ReadableState.prototype, 'pipesCount', {
170173
}
171174
});
172175

176+
// Legacy property for `paused`
177+
ObjectDefineProperty(ReadableState.prototype, 'paused', {
178+
get() {
179+
return this[kPaused] !== false;
180+
},
181+
set(value) {
182+
this[kPaused] = !!value;
183+
}
184+
});
185+
173186
function Readable(options) {
174187
if (!(this instanceof Readable))
175188
return new Readable(options);
@@ -365,7 +378,8 @@ function chunkInvalid(state, chunk) {
365378

366379

367380
Readable.prototype.isPaused = function() {
368-
return this._readableState.flowing === false;
381+
const state = this._readableState;
382+
return state[kPaused] === true || state.flowing === false;
369383
};
370384

371385
// Backwards compatibility.
@@ -962,14 +976,16 @@ function updateReadableListening(self) {
962976
const state = self._readableState;
963977
state.readableListening = self.listenerCount('readable') > 0;
964978

965-
if (state.resumeScheduled && !state.paused) {
979+
if (state.resumeScheduled && state[kPaused] === false) {
966980
// Flowing needs to be set to true now, otherwise
967981
// the upcoming resume will not flow.
968982
state.flowing = true;
969983

970984
// Crude way to check if we should resume
971985
} else if (self.listenerCount('data') > 0) {
972986
self.resume();
987+
} else if (!state.readableListening) {
988+
state.flowing = null;
973989
}
974990
}
975991

@@ -990,7 +1006,7 @@ Readable.prototype.resume = function() {
9901006
state.flowing = !state.readableListening;
9911007
resume(this, state);
9921008
}
993-
state.paused = false;
1009+
state[kPaused] = false;
9941010
return this;
9951011
};
9961012

@@ -1021,7 +1037,7 @@ Readable.prototype.pause = function() {
10211037
this._readableState.flowing = false;
10221038
this.emit('pause');
10231039
}
1024-
this._readableState.paused = true;
1040+
this._readableState[kPaused] = true;
10251041
return this;
10261042
};
10271043

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
const { Readable } = require('stream');
5+
6+
const readable = new Readable({
7+
read() {}
8+
});
9+
10+
function read() {}
11+
12+
readable.setEncoding('utf8');
13+
readable.on('readable', read);
14+
readable.removeListener('readable', read);
15+
16+
process.nextTick(function() {
17+
readable.on('data', common.mustCall());
18+
readable.push('hello');
19+
});

test/parallel/test-stream-readable-pause-and-resume.js

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const common = require('../common');
4+
const assert = require('assert');
45
const { Readable } = require('stream');
56

67
let ticks = 18;
@@ -38,3 +39,20 @@ function readAndPause() {
3839

3940
rs.on('data', ondata);
4041
}
42+
43+
{
44+
const readable = new Readable({
45+
read() {}
46+
});
47+
48+
function read() {}
49+
50+
readable.setEncoding('utf8');
51+
readable.on('readable', read);
52+
readable.removeListener('readable', read);
53+
readable.pause();
54+
55+
process.nextTick(function() {
56+
assert(readable.isPaused());
57+
});
58+
}

0 commit comments

Comments
 (0)