|
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