mirror of https://github.com/vuejs/core.git
fix(reactivity): prevent overwriting `next` property during batch processing (#12075)
close #12072
This commit is contained in:
parent
29de6f8b0b
commit
d3f5e6e531
|
@ -260,4 +260,21 @@ describe('watch', () => {
|
|||
src.value = 10
|
||||
expect(spy).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('should ensure correct execution order in batch processing', () => {
|
||||
const dummy: number[] = []
|
||||
const n1 = ref(0)
|
||||
const n2 = ref(0)
|
||||
const sum = computed(() => n1.value + n2.value)
|
||||
watch(n1, () => {
|
||||
dummy.push(1)
|
||||
n2.value++
|
||||
})
|
||||
watch(sum, () => dummy.push(2))
|
||||
watch(n1, () => dummy.push(3))
|
||||
|
||||
n1.value++
|
||||
|
||||
expect(dummy).toEqual([1, 2, 3])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -121,7 +121,7 @@ export class ComputedRefImpl<T = any> implements Subscriber {
|
|||
// avoid infinite self recursion
|
||||
activeSub !== this
|
||||
) {
|
||||
batch(this)
|
||||
batch(this, true)
|
||||
return true
|
||||
} else if (__DEV__) {
|
||||
// TODO warn
|
||||
|
|
|
@ -234,9 +234,15 @@ export class ReactiveEffect<T = any>
|
|||
|
||||
let batchDepth = 0
|
||||
let batchedSub: Subscriber | undefined
|
||||
let batchedComputed: Subscriber | undefined
|
||||
|
||||
export function batch(sub: Subscriber): void {
|
||||
export function batch(sub: Subscriber, isComputed = false): void {
|
||||
sub.flags |= EffectFlags.NOTIFIED
|
||||
if (isComputed) {
|
||||
sub.next = batchedComputed
|
||||
batchedComputed = sub
|
||||
return
|
||||
}
|
||||
sub.next = batchedSub
|
||||
batchedSub = sub
|
||||
}
|
||||
|
@ -257,24 +263,23 @@ export function endBatch(): void {
|
|||
return
|
||||
}
|
||||
|
||||
if (batchedComputed) {
|
||||
let e: Subscriber | undefined = batchedComputed
|
||||
batchedComputed = undefined
|
||||
while (e) {
|
||||
const next: Subscriber | undefined = e.next
|
||||
e.next = undefined
|
||||
e.flags &= ~EffectFlags.NOTIFIED
|
||||
e = next
|
||||
}
|
||||
}
|
||||
|
||||
let error: unknown
|
||||
while (batchedSub) {
|
||||
let e: Subscriber | undefined = batchedSub
|
||||
let next: Subscriber | undefined
|
||||
// 1st pass: clear notified flags for computed upfront
|
||||
// we use the ACTIVE flag as a discriminator between computed and effect,
|
||||
// since NOTIFIED is useless for an inactive effect anyway.
|
||||
while (e) {
|
||||
if (!(e.flags & EffectFlags.ACTIVE)) {
|
||||
e.flags &= ~EffectFlags.NOTIFIED
|
||||
}
|
||||
e = e.next
|
||||
}
|
||||
e = batchedSub
|
||||
batchedSub = undefined
|
||||
// 2nd pass: run effects
|
||||
while (e) {
|
||||
next = e.next
|
||||
const next: Subscriber | undefined = e.next
|
||||
e.next = undefined
|
||||
e.flags &= ~EffectFlags.NOTIFIED
|
||||
if (e.flags & EffectFlags.ACTIVE) {
|
||||
|
|
Loading…
Reference in New Issue