|
1 | 1 | import { TrackOpTypes, TriggerOpTypes } from './operations'
|
2 |
| -import { EMPTY_OBJ, extend, isArray } from '@vue/shared' |
| 2 | +import { EMPTY_OBJ, isArray } from '@vue/shared' |
3 | 3 |
|
4 | 4 | // The main WeakMap that stores {target -> key -> dep} connections.
|
5 | 5 | // Conceptually, it's easier to think of a dependency as a Dep class
|
@@ -43,7 +43,8 @@ export interface DebuggerEventExtraInfo {
|
43 | 43 | const effectStack: ReactiveEffect[] = []
|
44 | 44 | export let activeEffect: ReactiveEffect | undefined
|
45 | 45 |
|
46 |
| -export const ITERATE_KEY = Symbol('iterate') |
| 46 | +export const ITERATE_KEY = Symbol(__DEV__ ? 'iterate' : '') |
| 47 | +export const MAP_KEY_ITERATE_KEY = Symbol(__DEV__ ? 'Map key iterate' : '') |
47 | 48 |
|
48 | 49 | export function isEffect(fn: any): fn is ReactiveEffect {
|
49 | 50 | return fn && fn._isEffect === true
|
@@ -174,97 +175,78 @@ export function trigger(
|
174 | 175 | // never been tracked
|
175 | 176 | return
|
176 | 177 | }
|
| 178 | + |
177 | 179 | const effects = new Set<ReactiveEffect>()
|
178 | 180 | const computedRunners = new Set<ReactiveEffect>()
|
| 181 | + const add = (effectsToAdd: Set<ReactiveEffect> | undefined) => { |
| 182 | + if (effectsToAdd !== void 0) { |
| 183 | + effectsToAdd.forEach(effect => { |
| 184 | + if (effect !== activeEffect || !shouldTrack) { |
| 185 | + if (effect.options.computed) { |
| 186 | + computedRunners.add(effect) |
| 187 | + } else { |
| 188 | + effects.add(effect) |
| 189 | + } |
| 190 | + } else { |
| 191 | + // the effect mutated its own dependency during its execution. |
| 192 | + // this can be caused by operations like foo.value++ |
| 193 | + // do not trigger or we end in an infinite loop |
| 194 | + } |
| 195 | + }) |
| 196 | + } |
| 197 | + } |
| 198 | + |
179 | 199 | if (type === TriggerOpTypes.CLEAR) {
|
180 | 200 | // collection being cleared
|
181 | 201 | // trigger all effects for target
|
182 |
| - depsMap.forEach(dep => { |
183 |
| - addRunners(effects, computedRunners, dep) |
184 |
| - }) |
| 202 | + depsMap.forEach(add) |
185 | 203 | } else if (key === 'length' && isArray(target)) {
|
186 | 204 | depsMap.forEach((dep, key) => {
|
187 | 205 | if (key === 'length' || key >= (newValue as number)) {
|
188 |
| - addRunners(effects, computedRunners, dep) |
| 206 | + add(dep) |
189 | 207 | }
|
190 | 208 | })
|
191 | 209 | } else {
|
192 | 210 | // schedule runs for SET | ADD | DELETE
|
193 | 211 | if (key !== void 0) {
|
194 |
| - addRunners(effects, computedRunners, depsMap.get(key)) |
| 212 | + add(depsMap.get(key)) |
195 | 213 | }
|
196 | 214 | // also run for iteration key on ADD | DELETE | Map.SET
|
197 |
| - if ( |
| 215 | + const isAddOrDelete = |
198 | 216 | type === TriggerOpTypes.ADD ||
|
199 |
| - (type === TriggerOpTypes.DELETE && !isArray(target)) || |
| 217 | + (type === TriggerOpTypes.DELETE && !isArray(target)) |
| 218 | + if ( |
| 219 | + isAddOrDelete || |
200 | 220 | (type === TriggerOpTypes.SET && target instanceof Map)
|
201 | 221 | ) {
|
202 |
| - const iterationKey = isArray(target) ? 'length' : ITERATE_KEY |
203 |
| - addRunners(effects, computedRunners, depsMap.get(iterationKey)) |
| 222 | + add(depsMap.get(isArray(target) ? 'length' : ITERATE_KEY)) |
| 223 | + } |
| 224 | + if (isAddOrDelete && target instanceof Map) { |
| 225 | + add(depsMap.get(MAP_KEY_ITERATE_KEY)) |
204 | 226 | }
|
205 | 227 | }
|
| 228 | + |
206 | 229 | const run = (effect: ReactiveEffect) => {
|
207 |
| - scheduleRun( |
208 |
| - effect, |
209 |
| - target, |
210 |
| - type, |
211 |
| - key, |
212 |
| - __DEV__ |
213 |
| - ? { |
214 |
| - newValue, |
215 |
| - oldValue, |
216 |
| - oldTarget |
217 |
| - } |
218 |
| - : undefined |
219 |
| - ) |
| 230 | + if (__DEV__ && effect.options.onTrigger) { |
| 231 | + effect.options.onTrigger({ |
| 232 | + effect, |
| 233 | + target, |
| 234 | + key, |
| 235 | + type, |
| 236 | + newValue, |
| 237 | + oldValue, |
| 238 | + oldTarget |
| 239 | + }) |
| 240 | + } |
| 241 | + if (effect.options.scheduler !== void 0) { |
| 242 | + effect.options.scheduler(effect) |
| 243 | + } else { |
| 244 | + effect() |
| 245 | + } |
220 | 246 | }
|
| 247 | + |
221 | 248 | // Important: computed effects must be run first so that computed getters
|
222 | 249 | // can be invalidated before any normal effects that depend on them are run.
|
223 | 250 | computedRunners.forEach(run)
|
224 | 251 | effects.forEach(run)
|
225 | 252 | }
|
226 |
| - |
227 |
| -function addRunners( |
228 |
| - effects: Set<ReactiveEffect>, |
229 |
| - computedRunners: Set<ReactiveEffect>, |
230 |
| - effectsToAdd: Set<ReactiveEffect> | undefined |
231 |
| -) { |
232 |
| - if (effectsToAdd !== void 0) { |
233 |
| - effectsToAdd.forEach(effect => { |
234 |
| - if (effect !== activeEffect || !shouldTrack) { |
235 |
| - if (effect.options.computed) { |
236 |
| - computedRunners.add(effect) |
237 |
| - } else { |
238 |
| - effects.add(effect) |
239 |
| - } |
240 |
| - } else { |
241 |
| - // the effect mutated its own dependency during its execution. |
242 |
| - // this can be caused by operations like foo.value++ |
243 |
| - // do not trigger or we end in an infinite loop |
244 |
| - } |
245 |
| - }) |
246 |
| - } |
247 |
| -} |
248 |
| - |
249 |
| -function scheduleRun( |
250 |
| - effect: ReactiveEffect, |
251 |
| - target: object, |
252 |
| - type: TriggerOpTypes, |
253 |
| - key: unknown, |
254 |
| - extraInfo?: DebuggerEventExtraInfo |
255 |
| -) { |
256 |
| - if (__DEV__ && effect.options.onTrigger) { |
257 |
| - const event: DebuggerEvent = { |
258 |
| - effect, |
259 |
| - target, |
260 |
| - key, |
261 |
| - type |
262 |
| - } |
263 |
| - effect.options.onTrigger(extraInfo ? extend(event, extraInfo) : event) |
264 |
| - } |
265 |
| - if (effect.options.scheduler !== void 0) { |
266 |
| - effect.options.scheduler(effect) |
267 |
| - } else { |
268 |
| - effect() |
269 |
| - } |
270 |
| -} |
0 commit comments