|
|
@@ -1,7 +1,7 @@
|
|
|
import { extend, hasChanged } from '@vue/shared'
|
|
|
import type { ComputedRefImpl } from './computed'
|
|
|
import type { TrackOpTypes, TriggerOpTypes } from './constants'
|
|
|
-import { type Link, globalVersion, targetMap } from './dep'
|
|
|
+import { type Link, globalVersion } from './dep'
|
|
|
import { activeEffectScope } from './effectScope'
|
|
|
import { warn } from './warning'
|
|
|
|
|
|
@@ -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,6 +263,17 @@ 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
|
|
|
@@ -399,7 +416,7 @@ export function refreshComputed(computed: ComputedRefImpl): undefined {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function removeSub(link: Link, fromComputed = false) {
|
|
|
+function removeSub(link: Link, soft = false) {
|
|
|
const { dep, prevSub, nextSub } = link
|
|
|
if (prevSub) {
|
|
|
prevSub.nextSub = nextSub
|
|
|
@@ -418,21 +435,24 @@ function removeSub(link: Link, fromComputed = false) {
|
|
|
dep.subsHead = nextSub
|
|
|
}
|
|
|
|
|
|
- if (!dep.subs) {
|
|
|
- // last subscriber removed
|
|
|
- if (dep.computed) {
|
|
|
- // if computed, unsubscribe it from all its deps so this computed and its
|
|
|
- // value can be GCed
|
|
|
- dep.computed.flags &= ~EffectFlags.TRACKING
|
|
|
- for (let l = dep.computed.deps; l; l = l.nextDep) {
|
|
|
- removeSub(l, true)
|
|
|
- }
|
|
|
- } else if (dep.map && !fromComputed) {
|
|
|
- // property dep, remove it from the owner depsMap
|
|
|
- dep.map.delete(dep.key)
|
|
|
- if (!dep.map.size) targetMap.delete(dep.target!)
|
|
|
+ if (!dep.subs && dep.computed) {
|
|
|
+ // if computed, unsubscribe it from all its deps so this computed and its
|
|
|
+ // value can be GCed
|
|
|
+ dep.computed.flags &= ~EffectFlags.TRACKING
|
|
|
+ for (let l = dep.computed.deps; l; l = l.nextDep) {
|
|
|
+ // here we are only "soft" unsubscribing because the computed still keeps
|
|
|
+ // referencing the deps and the dep should not decrease its sub count
|
|
|
+ removeSub(l, true)
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if (!soft && !--dep.sc && dep.map) {
|
|
|
+ // #11979
|
|
|
+ // property dep no longer has effect subscribers, delete it
|
|
|
+ // this mostly is for the case where an object is kept in memory but only a
|
|
|
+ // subset of its properties is tracked at one time
|
|
|
+ dep.map.delete(dep.key)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function removeDep(link: Link) {
|