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'])
|
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 () => {
|
it('should dedupe queued jobs', async () => {
|
||||||
const calls: string[] = []
|
const calls: string[] = []
|
||||||
const job1 = () => {
|
const job1 = () => {
|
||||||
|
@ -57,6 +57,25 @@ export function nextTick(
|
|||||||
return fn ? p.then(this ? fn.bind(this) : fn) : p
|
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) {
|
export function queueJob(job: SchedulerJob) {
|
||||||
// the dedupe search uses the startIndex argument of Array.includes()
|
// the dedupe search uses the startIndex argument of Array.includes()
|
||||||
// by default the search index includes the current job that is being run
|
// by default the search index includes the current job that is being run
|
||||||
@ -72,7 +91,12 @@ export function queueJob(job: SchedulerJob) {
|
|||||||
)) &&
|
)) &&
|
||||||
job !== currentPreFlushParentJob
|
job !== currentPreFlushParentJob
|
||||||
) {
|
) {
|
||||||
queue.push(job)
|
const pos = findInsertionIndex(job)
|
||||||
|
if (pos > -1) {
|
||||||
|
queue.splice(pos, 0, job)
|
||||||
|
} else {
|
||||||
|
queue.push(job)
|
||||||
|
}
|
||||||
queueFlush()
|
queueFlush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user