refactor: sync value access for chained computed w/ scheduler
This commit is contained in:
@@ -201,10 +201,29 @@ describe('reactivity/computed', () => {
|
||||
})
|
||||
|
||||
describe('with scheduler', () => {
|
||||
const p = Promise.resolve()
|
||||
const defer = (fn?: any) => (fn ? p.then(fn) : p)
|
||||
// a simple scheduler similar to the main Vue scheduler
|
||||
const tick = Promise.resolve()
|
||||
const queue: any[] = []
|
||||
let queued = false
|
||||
|
||||
const schedule = (fn: any) => {
|
||||
queue.push(fn)
|
||||
if (!queued) {
|
||||
queued = true
|
||||
tick.then(flush)
|
||||
}
|
||||
}
|
||||
|
||||
const flush = () => {
|
||||
for (let i = 0; i < queue.length; i++) {
|
||||
queue[i]()
|
||||
}
|
||||
queue.length = 0
|
||||
queued = false
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
setComputedScheduler(defer)
|
||||
setComputedScheduler(schedule)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -224,7 +243,7 @@ describe('reactivity/computed', () => {
|
||||
src.value = 3
|
||||
// not called yet
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
await defer()
|
||||
await tick
|
||||
// should only trigger once
|
||||
expect(spy).toHaveBeenCalledTimes(2)
|
||||
expect(spy).toHaveBeenCalledWith(c.value)
|
||||
@@ -241,16 +260,67 @@ describe('reactivity/computed', () => {
|
||||
src.value = 1
|
||||
src.value = 2
|
||||
|
||||
await defer()
|
||||
await tick
|
||||
// should not trigger
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
|
||||
src.value = 3
|
||||
src.value = 4
|
||||
src.value = 5
|
||||
await defer()
|
||||
await tick
|
||||
// should trigger because latest value changes
|
||||
expect(spy).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('chained computed value invalidation', async () => {
|
||||
const effectSpy = jest.fn()
|
||||
const c1Spy = jest.fn()
|
||||
const c2Spy = jest.fn()
|
||||
|
||||
const src = ref(0)
|
||||
const c1 = computed(() => {
|
||||
c1Spy()
|
||||
return src.value % 2
|
||||
})
|
||||
const c2 = computed(() => {
|
||||
c2Spy()
|
||||
return c1.value + 1
|
||||
})
|
||||
|
||||
effect(() => {
|
||||
effectSpy(c2.value)
|
||||
})
|
||||
|
||||
expect(effectSpy).toHaveBeenCalledTimes(1)
|
||||
expect(effectSpy).toHaveBeenCalledWith(1)
|
||||
expect(c2.value).toBe(1)
|
||||
|
||||
expect(c1Spy).toHaveBeenCalledTimes(1)
|
||||
expect(c2Spy).toHaveBeenCalledTimes(1)
|
||||
|
||||
src.value = 1
|
||||
// value should be available sync
|
||||
expect(c2.value).toBe(2)
|
||||
expect(c2Spy).toHaveBeenCalledTimes(2)
|
||||
await tick
|
||||
expect(effectSpy).toHaveBeenCalledTimes(2)
|
||||
expect(effectSpy).toHaveBeenCalledWith(2)
|
||||
expect(c1Spy).toHaveBeenCalledTimes(2)
|
||||
expect(c2Spy).toHaveBeenCalledTimes(2)
|
||||
|
||||
src.value = 2
|
||||
await tick
|
||||
expect(effectSpy).toHaveBeenCalledTimes(3)
|
||||
expect(c1Spy).toHaveBeenCalledTimes(3)
|
||||
expect(c2Spy).toHaveBeenCalledTimes(3)
|
||||
|
||||
src.value = 4
|
||||
await tick
|
||||
expect(effectSpy).toHaveBeenCalledTimes(3)
|
||||
expect(c1Spy).toHaveBeenCalledTimes(4)
|
||||
// in-between chained computed always re-compute, but it does avoid
|
||||
// triggering the final subscribing effect.
|
||||
expect(c2Spy).toHaveBeenCalledTimes(4)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user