fix(scheduler): ensure updates are always inserted in ascending id order (#3184)
fix #2768, fix #2829
This commit is contained in:
parent
75964aba03
commit
45fae9d308
@ -44,6 +44,38 @@ describe('scheduler', () => {
|
||||
expect(calls).toEqual(['job1', 'job2'])
|
||||
})
|
||||
|
||||
it("should insert jobs in ascending order of job's id when flushing", async () => {
|
||||
const calls: string[] = []
|
||||
const job1 = () => {
|
||||
calls.push('job1')
|
||||
|
||||
queueJob(job2)
|
||||
queueJob(job3)
|
||||
queueJob(job4)
|
||||
}
|
||||
|
||||
const job2 = () => {
|
||||
calls.push('job2')
|
||||
}
|
||||
job2.id = 10
|
||||
|
||||
const job3 = () => {
|
||||
calls.push('job3')
|
||||
}
|
||||
job3.id = 1
|
||||
|
||||
// job4 gets the Infinity as it's id
|
||||
const job4 = () => {
|
||||
calls.push('job4')
|
||||
}
|
||||
|
||||
queueJob(job1)
|
||||
|
||||
expect(calls).toEqual([])
|
||||
await nextTick()
|
||||
expect(calls).toEqual(['job1', 'job3', 'job2', 'job4'])
|
||||
})
|
||||
|
||||
it('should dedupe queued jobs', async () => {
|
||||
const calls: string[] = []
|
||||
const job1 = () => {
|
||||
|
@ -57,6 +57,25 @@ export function nextTick(
|
||||
return fn ? p.then(this ? fn.bind(this) : fn) : p
|
||||
}
|
||||
|
||||
// #2768
|
||||
// Use binary-search to find a suitable position in the queue,
|
||||
// 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.
|
||||
function findInsertionIndex(job: SchedulerJob) {
|
||||
// the start index should be `flushIndex + 1`
|
||||
let start = flushIndex + 1
|
||||
let end = queue.length
|
||||
const jobId = getId(job)
|
||||
|
||||
while (start < end) {
|
||||
const middle = (start + end) >>> 1
|
||||
const middleJobId = getId(queue[middle])
|
||||
middleJobId < jobId ? (start = middle + 1) : (end = middle)
|
||||
}
|
||||
|
||||
return start
|
||||
}
|
||||
|
||||
export function queueJob(job: SchedulerJob) {
|
||||
// the dedupe search uses the startIndex argument of Array.includes()
|
||||
// by default the search index includes the current job that is being run
|
||||
@ -72,7 +91,12 @@ export function queueJob(job: SchedulerJob) {
|
||||
)) &&
|
||||
job !== currentPreFlushParentJob
|
||||
) {
|
||||
queue.push(job)
|
||||
const pos = findInsertionIndex(job)
|
||||
if (pos > -1) {
|
||||
queue.splice(pos, 0, job)
|
||||
} else {
|
||||
queue.push(job)
|
||||
}
|
||||
queueFlush()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user