Skip to content

Commit d17f233

Browse files
committed
stream: call _final synchronously
1 parent 283e7a4 commit d17f233

File tree

6 files changed

+35
-20
lines changed

6 files changed

+35
-20
lines changed

lib/_stream_writable.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -665,24 +665,26 @@ function needFinish(state) {
665665
}
666666

667667
function callFinal(stream, state) {
668+
state.sync = true;
668669
stream._final((err) => {
669670
state.pendingcb--;
670671
if (err) {
671-
errorOrDestroy(stream, err);
672+
errorOrDestroy(stream, err, state.sync);
672673
} else {
673674
state.prefinished = true;
674675
stream.emit('prefinish');
675-
finishMaybe(stream, state);
676+
finishMaybe(stream, state, state.sync);
676677
}
677678
});
679+
state.sync = false;
678680
}
679681

680682
function prefinish(stream, state) {
681683
if (!state.prefinished && !state.finalCalled) {
682684
if (typeof stream._final === 'function' && !state.destroyed) {
683685
state.pendingcb++;
684686
state.finalCalled = true;
685-
process.nextTick(callFinal, stream, state);
687+
callFinal(stream, state);
686688
} else {
687689
state.prefinished = true;
688690
stream.emit('prefinish');
@@ -691,10 +693,11 @@ function prefinish(stream, state) {
691693
}
692694

693695
function finishMaybe(stream, state, sync) {
694-
const need = needFinish(state);
696+
let need = needFinish(state);
695697
if (need) {
696698
prefinish(stream, state);
697-
if (state.pendingcb === 0) {
699+
need = needFinish(state);
700+
if (state.pendingcb === 0 && need) {
698701
state.pendingcb++;
699702
if (sync) {
700703
process.nextTick(finish, stream, state);

lib/internal/fs/streams.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ ObjectSetPrototypeOf(WriteStream, Writable);
366366
WriteStream.prototype._final = function(callback) {
367367
if (typeof this.fd !== 'number') {
368368
return this.once('open', function() {
369-
this._final(callback);
369+
process.nextTick(() => this._final(callback));
370370
});
371371
}
372372

lib/internal/http2/core.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,16 +2004,21 @@ class Http2Stream extends Duplex {
20042004
_final(cb) {
20052005
const handle = this[kHandle];
20062006
if (this.pending) {
2007-
this.once('ready', () => this._final(cb));
2007+
this.once('ready', function() {
2008+
process.nextTick(() => this._final(cb));
2009+
});
20082010
} else if (handle !== undefined) {
20092011
debugStreamObj(this, '_final shutting down');
2010-
const req = new ShutdownWrap();
2011-
req.oncomplete = afterShutdown;
2012-
req.callback = cb;
2013-
req.handle = handle;
2014-
const err = handle.shutdown(req);
2015-
if (err === 1) // synchronous finish
2016-
return afterShutdown.call(req, 0);
2012+
// TODO: Why does this need to be in nextTick?
2013+
process.nextTick(() => {
2014+
const req = new ShutdownWrap();
2015+
req.oncomplete = afterShutdown;
2016+
req.callback = cb;
2017+
req.handle = handle;
2018+
const err = handle.shutdown(req);
2019+
if (err === 1) // synchronous finish
2020+
return afterShutdown.call(req, 0);
2021+
});
20172022
} else {
20182023
cb();
20192024
}

lib/internal/streams/destroy.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ function undestroy() {
119119
}
120120
}
121121

122-
function errorOrDestroy(stream, err) {
122+
function errorOrDestroy(stream, err, sync) {
123123
// We have tests that rely on errors being emitted
124124
// in the same tick, so changing this is semver major.
125125
// For now when you opt-in to autoDestroy we allow
@@ -138,7 +138,12 @@ function errorOrDestroy(stream, err) {
138138
if (r) {
139139
r.errored = true;
140140
}
141-
emitErrorNT(stream, err);
141+
142+
if (sync) {
143+
process.nextTick(emitErrorNT, stream, err);
144+
} else {
145+
emitErrorNT(stream, err);
146+
}
142147
}
143148
}
144149

lib/net.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,9 @@ Socket.prototype._final = function(cb) {
398398
// If still connecting - defer handling `_final` until 'connect' will happen
399399
if (this.pending) {
400400
debug('_final: not yet connected');
401-
return this.once('connect', () => this._final(cb));
401+
return this.once('connect', function() {
402+
process.nextTick(() => this._final(cb));
403+
});
402404
}
403405

404406
if (!this._handle)

test/parallel/test-stream-transform-final-sync.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@ const t = new stream.Transform({
8282
process.nextTick(function() {
8383
state++;
8484
// fluchCallback part 2
85-
assert.strictEqual(state, 15);
85+
assert.strictEqual(state, 13);
8686
done();
8787
});
8888
}, 1)
8989
});
9090
t.on('finish', common.mustCall(function() {
9191
state++;
9292
// finishListener
93-
assert.strictEqual(state, 13);
93+
assert.strictEqual(state, 14);
9494
}, 1));
9595
t.on('end', common.mustCall(function() {
9696
state++;
@@ -106,5 +106,5 @@ t.write(4);
106106
t.end(7, common.mustCall(function() {
107107
state++;
108108
// endMethodCallback
109-
assert.strictEqual(state, 14);
109+
assert.strictEqual(state, 15);
110110
}, 1));

0 commit comments

Comments
 (0)