Skip to content

Commit 577edca

Browse files
authoredOct 3, 2024··
fix(scheduler): job ordering when the post queue is flushing (#12090)
1 parent 3a55c3e commit 577edca

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed
 

‎packages/runtime-core/__tests__/scheduler.spec.ts

+54
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,29 @@ describe('scheduler', () => {
441441
await nextTick()
442442
expect(calls).toEqual(['job1', 'job2', 'cb1', 'cb2'])
443443
})
444+
445+
test('jobs added during post flush are ordered correctly', async () => {
446+
const calls: string[] = []
447+
448+
const job1: SchedulerJob = () => {
449+
calls.push('job1')
450+
}
451+
job1.id = 1
452+
453+
const job2: SchedulerJob = () => {
454+
calls.push('job2')
455+
}
456+
job2.id = 2
457+
458+
queuePostFlushCb(() => {
459+
queueJob(job2)
460+
queueJob(job1)
461+
})
462+
463+
await nextTick()
464+
465+
expect(calls).toEqual(['job1', 'job2'])
466+
})
444467
})
445468

446469
test('sort job based on id', async () => {
@@ -758,6 +781,37 @@ describe('scheduler', () => {
758781
expect(spy).toHaveBeenCalledTimes(1)
759782
})
760783

784+
test('flushPreFlushCbs inside a post job', async () => {
785+
const calls: string[] = []
786+
const callsAfterFlush: string[] = []
787+
788+
const job1: SchedulerJob = () => {
789+
calls.push('job1')
790+
}
791+
job1.id = 1
792+
job1.flags! |= SchedulerJobFlags.PRE
793+
794+
const job2: SchedulerJob = () => {
795+
calls.push('job2')
796+
}
797+
job2.id = 2
798+
job2.flags! |= SchedulerJobFlags.PRE
799+
800+
queuePostFlushCb(() => {
801+
queueJob(job2)
802+
queueJob(job1)
803+
804+
// e.g. nested app.mount() call
805+
flushPreFlushCbs()
806+
callsAfterFlush.push(...calls)
807+
})
808+
809+
await nextTick()
810+
811+
expect(callsAfterFlush).toEqual(['job1', 'job2'])
812+
expect(calls).toEqual(['job1', 'job2'])
813+
})
814+
761815
it('nextTick should return promise', async () => {
762816
const fn = vi.fn(() => {
763817
return 1

‎packages/runtime-core/src/scheduler.ts

+7-15
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,8 @@ export interface SchedulerJob extends Function {
4040

4141
export type SchedulerJobs = SchedulerJob | SchedulerJob[]
4242

43-
let isFlushing = false
44-
let isFlushPending = false
45-
4643
const queue: SchedulerJob[] = []
47-
let flushIndex = 0
44+
let flushIndex = -1
4845

4946
const pendingPostFlushCbs: SchedulerJob[] = []
5047
let activePostFlushCbs: SchedulerJob[] | null = null
@@ -74,7 +71,7 @@ export function nextTick<T = void, R = void>(
7471
// watcher should be inserted immediately before the update job. This allows
7572
// watchers to be skipped if the component is unmounted by the parent update.
7673
function findInsertionIndex(id: number) {
77-
let start = isFlushing ? flushIndex + 1 : 0
74+
let start = flushIndex + 1
7875
let end = queue.length
7976

8077
while (start < end) {
@@ -115,8 +112,7 @@ export function queueJob(job: SchedulerJob): void {
115112
}
116113

117114
function queueFlush() {
118-
if (!isFlushing && !isFlushPending) {
119-
isFlushPending = true
115+
if (!currentFlushPromise) {
120116
currentFlushPromise = resolvedPromise.then(flushJobs)
121117
}
122118
}
@@ -141,8 +137,8 @@ export function queuePostFlushCb(cb: SchedulerJobs): void {
141137
export function flushPreFlushCbs(
142138
instance?: ComponentInternalInstance,
143139
seen?: CountMap,
144-
// if currently flushing, skip the current job itself
145-
i: number = isFlushing ? flushIndex + 1 : 0,
140+
// skip the current job
141+
i: number = flushIndex + 1,
146142
): void {
147143
if (__DEV__) {
148144
seen = seen || new Map()
@@ -211,8 +207,6 @@ const getId = (job: SchedulerJob): number =>
211207
job.id == null ? (job.flags! & SchedulerJobFlags.PRE ? -1 : Infinity) : job.id
212208

213209
function flushJobs(seen?: CountMap) {
214-
isFlushPending = false
215-
isFlushing = true
216210
if (__DEV__) {
217211
seen = seen || new Map()
218212
}
@@ -255,15 +249,13 @@ function flushJobs(seen?: CountMap) {
255249
}
256250
}
257251

258-
flushIndex = 0
252+
flushIndex = -1
259253
queue.length = 0
260254

261255
flushPostFlushCbs(seen)
262256

263-
isFlushing = false
264257
currentFlushPromise = null
265-
// some postFlushCb queued jobs!
266-
// keep flushing until it drains.
258+
// If new jobs have been added to either queue, keep flushing
267259
if (queue.length || pendingPostFlushCbs.length) {
268260
flushJobs(seen)
269261
}

0 commit comments

Comments
 (0)
Please sign in to comment.