Skip to content

Commit bb2a821

Browse files
committed
stream: readable track errorEmitted
1 parent f018384 commit bb2a821

File tree

4 files changed

+35
-14
lines changed

4 files changed

+35
-14
lines changed

lib/_stream_readable.js

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ function ReadableState(options, stream, isDuplex) {
117117
this.resumeScheduled = false;
118118
this.paused = true;
119119

120+
// True if the error was already emitted and should not be thrown again
121+
this.errorEmitted = false;
122+
120123
// Should close be emitted on destroy. Defaults to true.
121124
this.emitClose = options.emitClose !== false;
122125

lib/_stream_writable.js

+2
Original file line numberDiff line numberDiff line change
@@ -428,11 +428,13 @@ function onwriteError(stream, state, sync, er, cb) {
428428
// This can emit finish, and it will always happen
429429
// after error
430430
process.nextTick(finishMaybe, stream, state);
431+
stream._writableState.errorEmitted = true;
431432
errorOrDestroy(stream, er);
432433
} else {
433434
// The caller expect this to happen before if
434435
// it is async
435436
cb(er);
437+
stream._writableState.errorEmitted = true;
436438
errorOrDestroy(stream, er);
437439
// This can emit finish, but finish must
438440
// always follow error

lib/internal/streams/async_iterator.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ const createReadableStreamAsyncIterator = (stream) => {
132132
[kLastReject]: { value: null, writable: true },
133133
[kError]: { value: null, writable: true },
134134
[kEnded]: {
135-
value: stream._readableState.endEmitted,
135+
value: stream._readableState.endEmitted ||
136+
stream._readableState.errorEmitted,
136137
writable: true
137138
},
138139
// The function passed to new Promise is cached so we avoid allocating a new

lib/internal/streams/destroy.js

+28-13
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,32 @@
22

33
// Undocumented cb() API, needed for core, not for public API
44
function destroy(err, cb) {
5-
const readableDestroyed = this._readableState &&
6-
this._readableState.destroyed;
7-
const writableDestroyed = this._writableState &&
8-
this._writableState.destroyed;
5+
const rState = this._readableState;
6+
const wState = this._writableState;
7+
8+
const readableDestroyed = rState && rState.destroyed;
9+
const writableDestroyed = wState && wState.destroyed;
910

1011
if (readableDestroyed || writableDestroyed) {
1112
if (cb) {
1213
cb(err);
1314
} else if (err) {
14-
if (!this._writableState) {
15-
process.nextTick(emitErrorNT, this, err);
16-
} else if (!this._writableState.errorEmitted) {
17-
this._writableState.errorEmitted = true;
18-
process.nextTick(emitErrorNT, this, err);
15+
const errorEmitted = (rState && rState.errorEmitted) ||
16+
(wState && wState.errorEmitted);
17+
18+
if (errorEmitted) {
19+
return this;
20+
}
21+
22+
if (rState) {
23+
rState.errorEmitted = true;
1924
}
25+
26+
if (wState) {
27+
wState.errorEmitted = true;
28+
}
29+
30+
process.nextTick(emitErrorNT, this, err);
2031
}
2132

2233
return this;
@@ -25,13 +36,13 @@ function destroy(err, cb) {
2536
// We set destroyed to true before firing error callbacks in order
2637
// to make it re-entrance safe in case destroy() is called within callbacks
2738

28-
if (this._readableState) {
29-
this._readableState.destroyed = true;
39+
if (rState) {
40+
rState.destroyed = true;
3041
}
3142

3243
// If this is a duplex stream mark the writable part as destroyed as well
33-
if (this._writableState) {
34-
this._writableState.destroyed = true;
44+
if (wState) {
45+
wState.destroyed = true;
3546
}
3647

3748
this._destroy(err || null, (err) => {
@@ -74,6 +85,7 @@ function undestroy() {
7485
this._readableState.reading = false;
7586
this._readableState.ended = false;
7687
this._readableState.endEmitted = false;
88+
this._readableState.errorEmitted = false;
7789
}
7890

7991
if (this._writableState) {
@@ -107,6 +119,9 @@ function errorOrDestroy(stream, err) {
107119
if (wState) {
108120
wState.errorEmitted = true;
109121
}
122+
if (rState) {
123+
rState.errorEmitted = true;
124+
}
110125
stream.emit('error', err);
111126
}
112127
}

0 commit comments

Comments
 (0)