We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
入口
path:packages/reactivity/src/reactive.ts
packages/reactivity/src/reactive.ts
export const enum ReactiveFlags { // 初始都为undefined SKIP = '__v_skip', //无需响应的对象 IS_REACTIVE = '__v_isReactive', //响应式对象 IS_READONLY = '__v_isReadonly', //只读数据 RAW = '__v_raw' //取原始对象 } const enum TargetType { INVALID = 0, // 无效 COMMON = 1, // Array/Object COLLECTION = 2 // map/set/weakMap/weakSet }
export function reactive(target: object) { // 如果尝试观察只读代理,请返回只读版本。 if (target && (target as Target)[ReactiveFlags.IS_READONLY]) { return target } return createReactiveObject( target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap ) }
createReactiveObject
// 机翻下英文注释就能看明白... function createReactiveObject( target: Target, isReadonly: boolean,// reactive函数调用传参为false baseHandlers: ProxyHandler<any>, collectionHandlers: ProxyHandler<any>, proxyMap: WeakMap<Target, any> ) { if (!isObject(target)) { // if (__DEV__) { // console.warn(`value cannot be made reactive: ${String(target)}`) // } return target } // 目标已是代理,请返回它。 // 此处调用会触发getter if ( target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE]) ) { return target } // 目标已具有相应的代理 // 每个 proxy 都会被保存在 proxyMap const existingProxy = proxyMap.get(target) if (existingProxy) { return existingProxy } function targetTypeMap(rawType: string) { switch (rawType) { case 'Object': case 'Array': return TargetType.COMMON case 'Map': case 'Set': case 'WeakMap': case 'WeakSet': return TargetType.COLLECTION default: return TargetType.INVALID } } function getTargetType(value: Target) { return value[ReactiveFlags.SKIP] || !Object.isExtensible(value) ? TargetType.INVALID // 0 // toRawType => Object.prototype.toString.call(value).slice(8,-1) : targetTypeMap(toRawType(value)) // 1|2 } // 0直接返回target const targetType = getTargetType(target) if (targetType === TargetType.INVALID) { return target } // 添加代理 const proxy = new Proxy( target, // 1=>baseHandlers 2->collectionHandlers targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers ) // target -> proxy proxyMap.set(target, proxy) return proxy }
baseHandlers
packages/reactivity/src/baseHandlers.ts
export const mutableHandlers: ProxyHandler<object> = { get, set, deleteProperty, has, ownKeys }
getter
const get = createGetter() function createGetter(isReadonly = false, shallow = false) { return function get(target: Target, key: string | symbol, receiver: object) { if (key === ReactiveFlags.IS_REACTIVE) { return !isReadonly } else if (key === ReactiveFlags.IS_READONLY) { return isReadonly } else if ( // 如果key==='__v_raw' && receiver===reactiveMap(也就是上文的proxyMap).get(target) key === ReactiveFlags.RAW && receiver === (isReadonly ? shallow ? shallowReadonlyMap : readonlyMap : shallow ? shallowReactiveMap : reactiveMap ).get(target) ) { // 当target[__v_raw]取值时 返回target return target } // isArray = Array.is const targetIsArray = isArray(target) // hasOwn = Object.prototype.hasOwnProperty.call // 判断 target是数组,并且调用了数组的方法 // arrayInstrumentations是 一个对象{[数组方法]:function(){}} if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) { return Reflect.get(arrayInstrumentations, key, receiver) } const res = Reflect.get(target, key, receiver) // isSymbol = typeof val === 'symbol' const builtInSymbols = new Set( Object.getOwnPropertyNames(Symbol) .map(key => (Symbol as any)[key]) .filter(isSymbol) ) if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { // 如果key是Symbol,则判断key是否是symbol内置属性 // 否则判断key是否在__proto__,__v_isRef,__isVue属性上 return res } if (!isReadonly) { // 不是制只读 track(target, TrackOpTypes.GET, key) } if (shallow) { return res } if (isRef(res)) { // 判断是否被ref修饰过 // ref展开-不适用于数组+整数键。 const shouldUnwrap = !targetIsArray || !isIntegerKey(key) return shouldUnwrap ? res.value : res } if (isObject(res)) { // 将返回值也转换为代理。 // 我们在这里执行isObject检查以避免无效值警告。 // 这里还需要延迟访问只读和被动,以避免循环依赖。 // 返回proxy,并在上方判断该对象是否被代理,如果被代理直接返回改 return isReadonly ? readonly(res) : reactive(res) } return res } }
arrayInstrumentations:
arrayInstrumentations
function createArrayInstrumentations() { const instrumentations: Record<string, Function> = {} // instrument identity-sensitive Array methods to account for possible reactive // values ;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => { instrumentations[key] = function (this: unknown[], ...args: unknown[]) { const arr = toRaw(this) as any for (let i = 0, l = this.length; i < l; i++) { track(arr, TrackOpTypes.GET, i + '') } // 我们首先使用原始参数运行该方法(可能是被动的) const res = arr[key](...args) if (res === -1 || res === false) { // 如果不起作用,请使用原始值再次运行它。 return arr[key](...args.map(toRaw)) } else { return res } } }) //避免无限调用 ;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => { instrumentations[key] = function (this: unknown[], ...args: unknown[]) { pauseTracking() // 触发getter,获取原始值调用对应函数 const res = (toRaw(this) as any)[key].apply(this, args) resetTracking() return res } }) return instrumentations }
effect:
path:packages/reactivity/src/effect.ts
packages/reactivity/src/effect.ts
track:
let activeEffect // ReactiveEffect实例 let trackOpBit = 1 export function track(target: object, type: TrackOpTypes, key: unknown) { if (!isTracking()) { // 没有依赖 // 看到此处 ,如果是单纯的get、set 没有使用effect的话,建议跳过下面部分,直接看set return } // targetMap: target -> depsMap let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } // depsMap: key -> dep let dep = depsMap.get(key) const createDep = (effects?: ReactiveEffect[]): Dep => { // Set 防止重复 const dep = new Set<ReactiveEffect>(effects) as Dep // 用来标记该属性上次和本次在哪些effect中使用过,再通过对比进行删除和新增。 dep.w = 0 dep.n = 0 return dep } if (!dep) { depsMap.set(key, (dep = createDep())) } const eventInfo = __DEV__ ? // debugger用,不需要关注 { effect: activeEffect, target, type, key } : undefined trackEffects(dep, eventInfo) } export function isTracking() { return shouldTrack && activeEffect !== undefined } export function trackEffects( dep: Dep, debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { let shouldTrack = false // effectTrackDepth: 当前递归跟踪的effect数。 用来记录当前effect是第几层,每当有effect执行就++effectTrackDepth,执行完毕就--effectTrackDepth // maxMarkerBits=30:按位轨迹标记最多支持30级递归。选择此值是为了使现代JS引擎能够在所有平台上使用SMI。当递归深度更大时,返回到使用完全清理。 if (effectTrackDepth <= maxMarkerBits) { // 判断本次是否标记过 if (!newTracked(dep)) { // trackOpBit 可以理解为唯一ID dep.n |= trackOpBit // set newly tracked // 判断原来是否标记过 shouldTrack = !wasTracked(dep) } } else { // Full cleanup mode. shouldTrack = !dep.has(activeEffect!) } if (shouldTrack) { dep.add(activeEffect) activeEffect!.deps.push(dep) if (__DEV__ && activeEffect!.onTrack) { activeEffect!.onTrack( Object.assign( { effect: activeEffect! }, debuggerEventExtraInfo ) ) } } }
export function effect<T = any>( fn: () => T, options?: ReactiveEffectOptions ): ReactiveEffectRunner { if ((fn as ReactiveEffectRunner).effect) { // 拿到原始fn fn = (fn as ReactiveEffectRunner).effect.fn } const _effect = new ReactiveEffect(fn) if (options) { // extend = Object.assign extend(_effect, options) if (options.scope) recordEffectScope(_effect, options.scope) } if (!options || !options.lazy) { // 没有lazy参数,立即执行run _effect.run() } const runner = _effect.run.bind(_effect) as ReactiveEffectRunner runner.effect = _effect return runner }
ReactiveEffect
const effectStack=[] class ReactiveEffect { constructor(fn, scheduler = null, scope) { this.fn = fn; this.scheduler = scheduler; this.active = true; this.deps = []; // effectScope 相关处理逻辑 recordEffectScope(this, scope); } run() { if (!this.active) { // 没有激活,说明我们调用了effect stop 函数, return this.fn(); } if (!effectStack.includes(this)) { try { effectStack.push((activeEffect = this)); enableTracking(); // 根据递归的深度记录位数 trackOpBit = 1 << ++effectTrackDepth; if (effectTrackDepth <= maxMarkerBits) { // 给依赖打标记 initDepMarkers(this); } else { // 超过 maxMarkerBits 则 trackOpBit 的计算会超过最大整形的位数, // 降级为 cleanupEffect cleanupEffect(this); } return this.fn(); } finally { // fn执行完成之后 if (effectTrackDepth <= maxMarkerBits) { // 完成依赖标记 finalizeDepMarkers(this); } // 恢复到上一级 trackOpBit = 1 << --effectTrackDepth; resetTracking(); // 出栈 effectStack.pop(); const n = effectStack.length; // 指向栈最后一个 effect activeEffect = n > 0 ? effectStack[n - 1] : undefined; } } } stop() { if (this.active) { cleanupEffect(this); if (this.onStop) { this.onStop(); } this.active = false; } } } const initDepMarkers = ({ deps }) => { if (deps.length) { for (let i = 0; i < deps.length; i++) { deps[i].w |= trackOpBit; // 标记依赖已经被收集 } } };
例子:
get
Vue.createApp({ setup(){ const state=reactive({a:1}) effect(()=>{ console.log(state.a) }) return {state} } }).mount('#app')
proxyMap={target:proxy}
targetMap={target:depsMap}
depsMap={key:dep}
dep={Set[ReactiveEffect实例],n,w}
reactive
proxy
setter
effect
run
state.a
track
target,key
dep
deps
ReactiveEffect.deps
w,n
effectStack
activeEffect
Setter
function createSetter(shallow = false) { return function set( target: object, key: string | symbol, value: unknown, receiver: object ): boolean { let oldValue = (target as any)[key] if (!shallow && !isReadonly(value)) { // 获取新旧真实数据 value = toRaw(value) oldValue = toRaw(oldValue) if (!isArray(target) && isRef(oldValue) && !isRef(value)) { // 处理ref数据 oldValue.value = value return true } } else { // 在浅层模式下,无论是否是reactive,对象都按原样设置 } // 判断有效key const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key) const result = Reflect.set(target, key, value, receiver) // 如果目标是原型链中的某个东西,则不要触发 // receiver是proxy实例对象,原值为Proxy {...target} // 此时Reflect.set执行过后,receiver变为Proxy {key:value} // proxyMap中相应的target也更改为{key:value} // toRaw获取__v_raw,会触发getter,返回proxyMap.get(target) if (target === toRaw(receiver)) { if (!hadKey) { trigger(target, TriggerOpTypes.ADD, key, value) } else if (hasChanged(value, oldValue)) { // 对比新旧值是否改变 // hasChanged = !Object.is trigger(target, TriggerOpTypes.SET, key, value, oldValue) } } return result } }
trigger:
export function trigger( target: object, type: TriggerOpTypes, key?: unknown, newValue?: unknown, oldValue?: unknown, oldTarget?: Map<unknown, unknown> | Set<unknown> ) { const depsMap = targetMap.get(target) if (!depsMap) { // 没有被收集 return } let deps: (Dep | undefined)[] = [] if (type === TriggerOpTypes.CLEAR) { // 正在清除集合 // 触发target中所有effect deps = [...depsMap.values()] } else if (key === 'length' && isArray(target)) { // 对修改数组length的处理 depsMap.forEach((dep, key) => { if (key === 'length' || key >= (newValue as number)) { deps.push(dep) } }) } else { if (key !== void 0) { deps.push(depsMap.get(key)) } // 在ADD | DELETE | Map.SET 时也运行迭代键 switch (type) { case TriggerOpTypes.ADD: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } else if (isIntegerKey(key)) { // new index added to array -> length changes deps.push(depsMap.get('length')) } break case TriggerOpTypes.DELETE: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } break case TriggerOpTypes.SET: if (isMap(target)) { deps.push(depsMap.get(ITERATE_KEY)) } break } } const eventInfo = __DEV__ ? { target, type, key, newValue, oldValue, oldTarget } : undefined if (deps.length === 1) { if (deps[0]) { if (__DEV__) { triggerEffects(deps[0], eventInfo) } else { triggerEffects(deps[0]) } } } else { const effects: ReactiveEffect[] = [] for (const dep of deps) { if (dep) { effects.push(...dep) } } if (__DEV__) { triggerEffects(createDep(effects), eventInfo) } else { triggerEffects(createDep(effects)) } } }
triggerEffects:
export function triggerEffects( dep: Dep | ReactiveEffect[], debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { // spread into array for stabilization for (const effect of isArray(dep) ? dep : [...dep]) { // effect = ReactiveEffect{} // 遍历依赖执行 if (effect !== activeEffect || effect.allowRecurse) { if (__DEV__ && effect.onTrigger) { effect.onTrigger(extend({ effect }, debuggerEventExtraInfo)) } if (effect.scheduler) { effect.scheduler() } else { effect.run() } } } }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
vue-reactive
入口
path:
packages/reactivity/src/reactive.ts
createReactiveObject
baseHandlers
packages/reactivity/src/baseHandlers.ts
getter
arrayInstrumentations
:effect:
path:
packages/reactivity/src/effect.ts
track:
effect:
ReactiveEffect
例子:
get
了proxyMap={target:proxy}
、targetMap={target:depsMap}
、depsMap={key:dep}
、dep={Set[ReactiveEffect实例],n,w}
reactive
:创建proxy
,getter
中收集依赖,setter
中触发effect
,effect
:创建ReactiveEffect
实例,执行run
函数,state.a
触发getter
,触发track
,根据target,key
找出对应dep
,将ReactiveEffect
实例添加进dep
,ReactiveEffect
实例deps
数组推入dep
ReactiveEffect.deps
,也就是dep
,更w,n
属性,effectStack
出栈,activeEffect
指向effectStack
栈顶Setter
trigger:
triggerEffects:
The text was updated successfully, but these errors were encountered: