Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit 9bb2b67

Browse files
committed
timers: fix processing of nested same delay timers
Whenever a timer with a specific timeout value creates a new timer with the same timeout, the newly added timer might be processed immediately in the same tick of the event loop instead of during the next tick of the event loop at the earliest. Fixes #25607
1 parent e192f61 commit 9bb2b67

File tree

1 file changed

+28
-6
lines changed

1 file changed

+28
-6
lines changed

lib/timers.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,35 @@ function listOnTimeout() {
8787

8888
var first;
8989
while (first = L.peek(list)) {
90-
// If the previous iteration caused a timer to be added,
91-
// update the value of "now" so that timing computations are
92-
// done correctly. See test/simple/test-timers-blocking-callback.js
93-
// for more information.
90+
// This handles the case of a timer that was created within a timers
91+
// callback with the same timeout value. For instance, when processing the
92+
// timer that would call `bar` in such code:
93+
//
94+
// setTimeout(function foo() { setTimeout(function bar() {}, 0) }, 0);
95+
//
96+
// or
97+
//
98+
// setTimeout(function foo() { setTimeout(function bar() {}, 500) }, 500);
99+
//
100+
// We want to make sure that newly added timer fires in the next turn of the
101+
// event loop at the earliest. So even if it's already expired now,
102+
// reschedule it to fire later.
103+
//
104+
// At that point, it's not necessary to process any other timer in that
105+
// list, because any remaining timer has been added within a callback of a
106+
// timer that has already been processed, and thus needs to be processed at
107+
// the earliest not in the current tick, but when the rescheduled timer will
108+
// expire.
109+
//
110+
// See: https://github.com/joyent/node/issues/25607
94111
if (now < first._monotonicStartTime) {
95-
now = Timer.now();
96-
debug('now: %d', now);
112+
var timeRemaining = msecs - (Timer.now() - first._monotonicStartTime);
113+
if (timeRemaining < 0) {
114+
timeRemaining = 0;
115+
}
116+
debug(msecs + ' list wait because timer was added from another timer');
117+
list.start(timeRemaining, 0);
118+
return;
97119
}
98120

99121
var diff = now - first._monotonicStartTime;

0 commit comments

Comments
 (0)