Skip to content

Commit a62d4d6

Browse files
ronagtargos
authored andcommittedSep 4, 2021
stream: add readableDidRead if has been read from
Adds did read accessor used to determine whether a readable has been read from. PR-URL: #39589 Refs: nodejs/undici#907 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 989c204 commit a62d4d6

File tree

3 files changed

+133
-1
lines changed

3 files changed

+133
-1
lines changed
 

‎doc/api/stream.md

+11
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,17 @@ added: v11.4.0
12111211
Is `true` if it is safe to call [`readable.read()`][stream-read], which means
12121212
the stream has not been destroyed or emitted `'error'` or `'end'`.
12131213

1214+
##### `readable.readableDidRead`
1215+
<!-- YAML
1216+
added: REPLACEME
1217+
-->
1218+
1219+
* {boolean}
1220+
1221+
Allows determining if the stream has been or is about to be read.
1222+
Returns true if `'data'`, `'end'`, `'error'` or `'close'` has been
1223+
emitted.
1224+
12141225
##### `readable.readableEncoding`
12151226
<!-- YAML
12161227
added: v12.7.0

‎lib/internal/streams/readable.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ function ReadableState(options, stream, isDuplex) {
154154
// If true, a maybeReadMore has been scheduled.
155155
this.readingMore = false;
156156

157+
this.dataEmitted = false;
158+
157159
this.decoder = null;
158160
this.encoding = null;
159161
if (options && options.encoding) {
@@ -287,6 +289,7 @@ function addChunk(stream, state, chunk, addToFront) {
287289
} else {
288290
state.awaitDrainWriters = null;
289291
}
292+
state.dataEmitted = true;
290293
stream.emit('data', chunk);
291294
} else {
292295
// Update the buffer info.
@@ -496,8 +499,10 @@ Readable.prototype.read = function(n) {
496499
endReadable(this);
497500
}
498501

499-
if (ret !== null)
502+
if (ret !== null) {
503+
state.dataEmitted = true;
500504
this.emit('data', ret);
505+
}
501506

502507
return ret;
503508
};
@@ -1169,6 +1174,18 @@ ObjectDefineProperties(Readable.prototype, {
11691174
}
11701175
},
11711176

1177+
readableDidRead: {
1178+
enumerable: false,
1179+
get: function() {
1180+
return (
1181+
this._readableState.dataEmitted ||
1182+
this._readableState.endEmitted ||
1183+
this._readableState.errorEmitted ||
1184+
this._readableState.closeEmitted
1185+
);
1186+
}
1187+
},
1188+
11721189
readableHighWaterMark: {
11731190
enumerable: false,
11741191
get: function() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const Readable = require('stream').Readable;
5+
6+
function noop() {}
7+
8+
function check(readable, data, fn) {
9+
assert.strictEqual(readable.readableDidRead, false);
10+
if (data === -1) {
11+
readable.on('error', common.mustCall());
12+
readable.on('data', common.mustNotCall());
13+
readable.on('end', common.mustNotCall());
14+
} else {
15+
readable.on('error', common.mustNotCall());
16+
if (data === -2) {
17+
readable.on('end', common.mustNotCall());
18+
} else {
19+
readable.on('end', common.mustCall());
20+
}
21+
if (data > 0) {
22+
readable.on('data', common.mustCallAtLeast(data));
23+
} else {
24+
readable.on('data', common.mustNotCall());
25+
}
26+
}
27+
readable.on('close', common.mustCall());
28+
fn();
29+
setImmediate(() => {
30+
assert.strictEqual(readable.readableDidRead, true);
31+
});
32+
}
33+
34+
{
35+
const readable = new Readable({
36+
read() {
37+
this.push(null);
38+
}
39+
});
40+
check(readable, 0, () => {
41+
readable.read();
42+
});
43+
}
44+
45+
{
46+
const readable = new Readable({
47+
read() {
48+
this.push(null);
49+
}
50+
});
51+
check(readable, 0, () => {
52+
readable.resume();
53+
});
54+
}
55+
56+
{
57+
const readable = new Readable({
58+
read() {
59+
this.push(null);
60+
}
61+
});
62+
check(readable, -2, () => {
63+
readable.destroy();
64+
});
65+
}
66+
67+
{
68+
const readable = new Readable({
69+
read() {
70+
this.push(null);
71+
}
72+
});
73+
74+
check(readable, -1, () => {
75+
readable.destroy(new Error());
76+
});
77+
}
78+
79+
{
80+
const readable = new Readable({
81+
read() {
82+
this.push('data');
83+
this.push(null);
84+
}
85+
});
86+
87+
check(readable, 1, () => {
88+
readable.on('data', noop);
89+
});
90+
}
91+
92+
{
93+
const readable = new Readable({
94+
read() {
95+
this.push('data');
96+
this.push(null);
97+
}
98+
});
99+
100+
check(readable, 1, () => {
101+
readable.on('data', noop);
102+
readable.off('data', noop);
103+
});
104+
}

0 commit comments

Comments
 (0)
Please sign in to comment.