diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 6b18318dd1d..16a90c6fb49 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -169,9 +169,6 @@ export class ReactiveEffect ) { return } - if (this.flags & EffectFlags.NO_BATCH) { - return this.trigger() - } if (!(this.flags & EffectFlags.NOTIFIED)) { this.flags |= EffectFlags.NOTIFIED this.nextEffect = batchedEffect @@ -180,8 +177,6 @@ export class ReactiveEffect } run(): T { - // TODO cleanupEffect - if (!(this.flags & EffectFlags.ACTIVE)) { // stopped during cleanup return this.fn() @@ -249,12 +244,13 @@ export class ReactiveEffect let batchDepth = 0 let batchedEffect: ReactiveEffect | undefined +let needBatch = true /** * @internal */ export function startBatch(): void { - batchDepth++ + needBatch && batchDepth++ } /** @@ -262,7 +258,7 @@ export function startBatch(): void { * @internal */ export function endBatch(): void { - if (batchDepth > 1) { + if (batchDepth > 1 && needBatch) { batchDepth-- return } @@ -277,16 +273,19 @@ export function endBatch(): void { e.flags &= ~EffectFlags.NOTIFIED if (e.flags & EffectFlags.ACTIVE) { try { + needBatch = !(e.flags & EffectFlags.NO_BATCH) e.trigger() } catch (err) { if (!error) error = err + } finally { + if (!needBatch) needBatch = true } } e = next } } - batchDepth-- + needBatch && batchDepth-- if (error) throw error } diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 85afec24ceb..53b853fdea0 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -1856,4 +1856,16 @@ describe('api: watch', () => { warn.mockRestore() }) + + it('sync watch callback order', () => { + const num = ref(1) + let result = '' + + for (let i = 0; i < 5; i++) { + watch(num, () => (result += i), { flush: 'sync' }) + } + expect(result).toBe('') + num.value++ + expect(result).toBe('01234') + }) })