From b332f80f0edb018229a23b43b93bb402b6368a3c Mon Sep 17 00:00:00 2001 From: skirtle <65301168+skirtles-code@users.noreply.github.com> Date: Mon, 19 Aug 2024 03:13:50 +0100 Subject: [PATCH] fix(runtime-core): pre jobs without an id should run first (#7746) --- .../runtime-core/__tests__/scheduler.spec.ts | 41 ++++++++++++++++++- packages/runtime-core/src/scheduler.ts | 14 +++---- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/packages/runtime-core/__tests__/scheduler.spec.ts b/packages/runtime-core/__tests__/scheduler.spec.ts index 079ced4bd1a..8d74330da44 100644 --- a/packages/runtime-core/__tests__/scheduler.spec.ts +++ b/packages/runtime-core/__tests__/scheduler.spec.ts @@ -239,6 +239,37 @@ describe('scheduler', () => { expect(calls).toEqual(['cb1', 'cb2', 'job1']) }) + it('should insert pre jobs without ids first during flushing', async () => { + const calls: string[] = [] + const job1: SchedulerJob = () => { + calls.push('job1') + queueJob(job3) + queueJob(job4) + } + // job1 has no id + job1.flags! |= SchedulerJobFlags.PRE + const job2: SchedulerJob = () => { + calls.push('job2') + } + job2.id = 1 + job2.flags! |= SchedulerJobFlags.PRE + const job3: SchedulerJob = () => { + calls.push('job3') + } + // job3 has no id + job3.flags! |= SchedulerJobFlags.PRE + const job4: SchedulerJob = () => { + calls.push('job4') + } + // job4 has no id + job4.flags! |= SchedulerJobFlags.PRE + + queueJob(job1) + queueJob(job2) + await nextTick() + expect(calls).toEqual(['job1', 'job3', 'job4', 'job2']) + }) + // #3806 it('queue preFlushCb inside postFlushCb', async () => { const spy = vi.fn() @@ -448,12 +479,20 @@ describe('scheduler', () => { job2.id = 2 const job3 = () => calls.push('job3') job3.id = 1 + const job4: SchedulerJob = () => calls.push('job4') + job4.id = 2 + job4.flags! |= SchedulerJobFlags.PRE + const job5: SchedulerJob = () => calls.push('job5') + // job5 has no id + job5.flags! |= SchedulerJobFlags.PRE queueJob(job1) queueJob(job2) queueJob(job3) + queueJob(job4) + queueJob(job5) await nextTick() - expect(calls).toEqual(['job3', 'job2', 'job1']) + expect(calls).toEqual(['job5', 'job3', 'job4', 'job2', 'job1']) }) test('sort SchedulerCbs based on id', async () => { diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index 354ebb3a4e8..bcad9962996 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -92,16 +92,16 @@ function findInsertionIndex(id: number) { export function queueJob(job: SchedulerJob): void { if (!(job.flags! & SchedulerJobFlags.QUEUED)) { - if (job.id == null) { - queue.push(job) - } else if ( + const jobId = getId(job) + const lastJob = queue[queue.length - 1] + if ( + !lastJob || // fast path when the job id is larger than the tail - !(job.flags! & SchedulerJobFlags.PRE) && - job.id >= ((queue[queue.length - 1] && queue[queue.length - 1].id) || 0) + (!(job.flags! & SchedulerJobFlags.PRE) && jobId >= getId(lastJob)) ) { queue.push(job) } else { - queue.splice(findInsertionIndex(job.id), 0, job) + queue.splice(findInsertionIndex(jobId), 0, job) } if (!(job.flags! & SchedulerJobFlags.ALLOW_RECURSE)) { @@ -206,7 +206,7 @@ export function flushPostFlushCbs(seen?: CountMap): void { } const getId = (job: SchedulerJob): number => - job.id == null ? Infinity : job.id + job.id == null ? (job.flags! & SchedulerJobFlags.PRE ? -1 : Infinity) : job.id const comparator = (a: SchedulerJob, b: SchedulerJob): number => { const diff = getId(a) - getId(b)