fix(scheduler): fix insertion for id-less job

fix #4148
This commit is contained in:
Evan You 2021-07-19 13:37:35 -04:00
parent 6eb47f000a
commit d810a1a569
2 changed files with 14 additions and 10 deletions

View File

@ -51,11 +51,12 @@ describe('scheduler', () => {
queueJob(job2) queueJob(job2)
queueJob(job3) queueJob(job3)
queueJob(job4)
} }
const job2 = () => { const job2 = () => {
calls.push('job2') calls.push('job2')
queueJob(job4)
queueJob(job5)
} }
job2.id = 10 job2.id = 10
@ -64,16 +65,19 @@ describe('scheduler', () => {
} }
job3.id = 1 job3.id = 1
// job4 gets the Infinity as it's id
const job4 = () => { const job4 = () => {
calls.push('job4') calls.push('job4')
} }
const job5 = () => {
calls.push('job5')
}
queueJob(job1) queueJob(job1)
expect(calls).toEqual([]) expect(calls).toEqual([])
await nextTick() await nextTick()
expect(calls).toEqual(['job1', 'job3', 'job2', 'job4']) expect(calls).toEqual(['job1', 'job3', 'job2', 'job4', 'job5'])
}) })
it('should dedupe queued jobs', async () => { it('should dedupe queued jobs', async () => {

View File

@ -10,6 +10,7 @@ setComputedScheduler(queueJob)
export interface SchedulerJob extends Function { export interface SchedulerJob extends Function {
id?: number id?: number
active?: boolean active?: boolean
computed?: boolean
/** /**
* Indicates whether the effect is allowed to recursively trigger itself * Indicates whether the effect is allowed to recursively trigger itself
* when managed by the scheduler. * when managed by the scheduler.
@ -70,16 +71,15 @@ export function nextTick<T = void>(
// Use binary-search to find a suitable position in the queue, // Use binary-search to find a suitable position in the queue,
// so that the queue maintains the increasing order of job's id, // so that the queue maintains the increasing order of job's id,
// which can prevent the job from being skipped and also can avoid repeated patching. // which can prevent the job from being skipped and also can avoid repeated patching.
function findInsertionIndex(job: SchedulerJob) { function findInsertionIndex(id: number) {
// the start index should be `flushIndex + 1` // the start index should be `flushIndex + 1`
let start = flushIndex + 1 let start = flushIndex + 1
let end = queue.length let end = queue.length
const jobId = getId(job)
while (start < end) { while (start < end) {
const middle = (start + end) >>> 1 const middle = (start + end) >>> 1
const middleJobId = getId(queue[middle]) const middleJobId = getId(queue[middle])
middleJobId < jobId ? (start = middle + 1) : (end = middle) middleJobId < id ? (start = middle + 1) : (end = middle)
} }
return start return start
@ -100,11 +100,10 @@ export function queueJob(job: SchedulerJob) {
)) && )) &&
job !== currentPreFlushParentJob job !== currentPreFlushParentJob
) { ) {
const pos = findInsertionIndex(job) if (job.id == null) {
if (pos > -1) {
queue.splice(pos, 0, job)
} else {
queue.push(job) queue.push(job)
} else {
queue.splice(findInsertionIndex(job.id), 0, job)
} }
queueFlush() queueFlush()
} }
@ -253,6 +252,7 @@ function flushJobs(seen?: CountMap) {
if (__DEV__ && checkRecursiveUpdates(seen!, job)) { if (__DEV__ && checkRecursiveUpdates(seen!, job)) {
continue continue
} }
// console.log(`running:`, job.id)
callWithErrorHandling(job, null, ErrorCodes.SCHEDULER) callWithErrorHandling(job, null, ErrorCodes.SCHEDULER)
} }
} }