Skip to content

Commit 31d86e6

Browse files
committed
clean up fast-immediate
1 parent e2bbf4b commit 31d86e6

File tree

1 file changed

+57
-107
lines changed

1 file changed

+57
-107
lines changed

packages/next/src/server/app-render/fast-set-immediate.external.ts

Lines changed: 57 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -23,91 +23,57 @@ export function install() {
2323

2424
export function runPendingImmediatesAfterCurrentTask() {
2525
startCapturingImmediates()
26+
scheduleWorkAfterTicksAndMicrotasks()
27+
}
2628

27-
const scheduleWorkAfterTicksAndMicrotasks = () => {
28-
originalNextTick(() => {
29-
queueMicrotask(() => {
30-
originalNextTick(() => {
31-
if (pendingNextTicks > 0) {
32-
// We have raw nextTicks. Let those run first.
33-
debug?.(`scheduler :: yielding to ${pendingNextTicks} nextTicks`)
34-
return scheduleWorkAfterTicksAndMicrotasks()
35-
}
36-
37-
return performWork()
38-
})
29+
function scheduleWorkAfterTicksAndMicrotasks() {
30+
originalNextTick(() => {
31+
queueMicrotask(() => {
32+
originalNextTick(() => {
33+
if (pendingNextTicks > 0) {
34+
// We have raw nextTicks. Let those run first.
35+
debug?.(`scheduler :: yielding to ${pendingNextTicks} nextTicks`)
36+
return scheduleWorkAfterTicksAndMicrotasks()
37+
}
38+
39+
return performWork()
3940
})
4041
})
41-
}
42+
})
43+
}
4244

43-
const performWork = () => {
44-
debug?.(`scheduler :: performing work`)
45+
function performWork() {
46+
debug?.(`scheduler :: performing work`)
4547

46-
// Find the first (if any) queued immediate that wasn't cleared
47-
let queueItem: ActiveQueueItem | null = null
48-
while (queuedImmediates.length) {
49-
const maybeQueItem = queuedImmediates.shift()!
50-
if (!maybeQueItem.isCleared) {
51-
queueItem = maybeQueItem
52-
break
53-
}
54-
}
55-
if (!queueItem) {
56-
debug?.(`scheduler :: no immediates queued, exiting`)
57-
stopCapturingImmediates()
58-
return
48+
// Find the first (if any) queued immediate that wasn't cleared
49+
let queueItem: ActiveQueueItem | null = null
50+
while (queuedImmediates.length) {
51+
const maybeQueItem = queuedImmediates.shift()!
52+
if (!maybeQueItem.isCleared) {
53+
queueItem = maybeQueItem
54+
break
5955
}
60-
61-
const { immediateObject, callback, args } = queueItem
62-
63-
// note that this is not a real Immediate object, because we're running them in a nextTick
64-
// TODO: we're already in our own tick, do we need another one?
65-
const handle = args
66-
? scheduleImmediateInNextTickAndContinueLoop(callback, ...args)
67-
: scheduleImmediateInNextTickAndContinueLoop(callback)
68-
69-
// Now that we're no longer buffering the immediate,
70-
// make the BufferedImmediate proxy calls to the native object instead
71-
immediateObject[INTERNALS].queueItem = null
72-
immediateObject[INTERNALS].nativeImmediate = handle
73-
clearQueueItem(queueItem)
56+
}
57+
if (!queueItem) {
58+
debug?.(`scheduler :: no immediates queued, exiting`)
59+
stopCapturingImmediates()
60+
return
7461
}
7562

76-
const scheduleImmediateInNextTickAndContinueLoop = (
77-
callback: (...args: any[]) => any,
78-
...args: any[]
79-
) => {
80-
let isCleared = false
63+
const { immediateObject, callback, args } = queueItem
8164

82-
originalNextTick(() => {
83-
// schedule the loop again in case there's more immediates after this.
84-
scheduleWorkAfterTicksAndMicrotasks()
65+
immediateObject[INTERNALS].queueItem = null
66+
clearQueueItem(queueItem)
8567

86-
if (isCleared) return
87-
callback.apply(null, args)
88-
})
68+
// schedule the loop again in case there's more immediates after this.
69+
scheduleWorkAfterTicksAndMicrotasks()
8970

90-
const handle = {
91-
ref() {
92-
return this
93-
},
94-
unref() {
95-
return this
96-
},
97-
hasRef() {
98-
return true
99-
},
100-
_onImmediate() {},
101-
102-
[Symbol.dispose]() {
103-
isCleared = true
104-
},
105-
} satisfies NodeJS.Immediate
106-
107-
return handle
71+
// execute the callback.
72+
if (args) {
73+
callback.apply(null, args)
74+
} else {
75+
callback()
10876
}
109-
110-
scheduleWorkAfterTicksAndMicrotasks()
11177
}
11278

11379
function startCapturingImmediates() {
@@ -132,14 +98,12 @@ type ActiveQueueItem = {
13298
isCleared: false
13399
callback: (...args: any[]) => any
134100
args: any[] | null
135-
hasRef: boolean
136-
immediateObject: BufferedImmediate
101+
immediateObject: NextImmediate
137102
}
138103
type ClearedQueueItem = {
139104
isCleared: true
140105
callback: null
141106
args: null
142-
hasRef: null
143107
immediateObject: null
144108
}
145109

@@ -148,7 +112,6 @@ function clearQueueItem(originalQueueItem: QueueItem) {
148112
queueItem.isCleared = true
149113
queueItem.callback = null
150114
queueItem.args = null
151-
queueItem.hasRef = null
152115
queueItem.immediateObject = null
153116
}
154117

@@ -220,13 +183,12 @@ function patchedSetImmediate(): NodeJS.Immediate {
220183
let args: any[] | null =
221184
arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : null
222185

223-
const immediateObject = new BufferedImmediate()
186+
const immediateObject = new NextImmediate()
224187

225188
const queueItem: ActiveQueueItem = {
226189
isCleared: false,
227190
callback,
228191
args,
229-
hasRef: true,
230192
immediateObject,
231193
}
232194
queuedImmediates.push(queueItem)
@@ -256,9 +218,9 @@ function patchedSetImmediatePromisify<T = void>(
256218
}
257219

258220
const immediate = patchedSetImmediate(resolve, value)
259-
if (options?.ref === false) {
260-
immediate.unref()
261-
}
221+
222+
// Note that we're ignoring `options.ref`, because `unref()` has no effect
223+
// on our patched immediates
262224

263225
if (signal) {
264226
signal.addEventListener(
@@ -279,7 +241,7 @@ const patchedClearImmediate = (
279241
immediateObject: NodeJS.Immediate | undefined
280242
) => {
281243
if (immediateObject && INTERNALS in immediateObject) {
282-
;(immediateObject as BufferedImmediate)[Symbol.dispose]()
244+
;(immediateObject as NextImmediate)[Symbol.dispose]()
283245
} else {
284246
originalClearImmediate(immediateObject)
285247
}
@@ -289,50 +251,41 @@ const patchedClearImmediate = (
289251

290252
const INTERNALS: unique symbol = Symbol.for('next.Immediate.internals')
291253

292-
type QueuedImmediateInternals =
293-
| {
294-
queueItem: ActiveQueueItem | null
295-
nativeImmediate: null
296-
}
297-
| {
298-
queueItem: null
299-
nativeImmediate: NodeJS.Immediate
300-
}
254+
type NextImmediateInternals = {
255+
/** Stored to reflect `ref()`/`unref()` calls, but has no effect otherwise */
256+
hasRef: boolean
257+
queueItem: ActiveQueueItem | null
258+
}
301259

302260
/** Makes sure that we're implementing all the public `Immediate` methods */
303261
interface NativeImmediate extends NodeJS.Immediate {}
304262

305263
/** Implements a shim for the native `Immediate` class returned by `setImmediate` */
306-
class BufferedImmediate implements NativeImmediate {
307-
[INTERNALS]: QueuedImmediateInternals = {
264+
class NextImmediate implements NativeImmediate {
265+
[INTERNALS]: NextImmediateInternals = {
308266
queueItem: null,
309-
nativeImmediate: null,
267+
hasRef: true,
310268
}
311269
hasRef() {
312270
const internals = this[INTERNALS]
313271
if (internals.queueItem) {
314-
return internals.queueItem.hasRef
315-
} else if (internals.nativeImmediate) {
316-
return internals.nativeImmediate.hasRef()
272+
return internals.hasRef
317273
} else {
274+
// if we're no longer queued (cleared or executed), hasRef is always false
318275
return false
319276
}
320277
}
321278
ref() {
322279
const internals = this[INTERNALS]
323280
if (internals.queueItem) {
324-
internals.queueItem.hasRef = true
325-
} else if (internals.nativeImmediate) {
326-
internals.nativeImmediate.ref()
281+
internals.hasRef = true
327282
}
328283
return this
329284
}
330285
unref() {
331286
const internals = this[INTERNALS]
332287
if (internals.queueItem) {
333-
internals.queueItem.hasRef = false
334-
} else if (internals.nativeImmediate) {
335-
internals.nativeImmediate.unref()
288+
internals.hasRef = false
336289
}
337290
return this
338291
}
@@ -348,9 +301,6 @@ class BufferedImmediate implements NativeImmediate {
348301
const queueItem = internals.queueItem
349302
internals.queueItem = null
350303
clearQueueItem(queueItem)
351-
} else if (internals.nativeImmediate) {
352-
// If we executed the queue, and we have a native immediate.
353-
originalClearImmediate(internals.nativeImmediate)
354304
}
355305
}
356306
}

0 commit comments

Comments
 (0)