vue3 Reactivity是一个响应式独立的包,其中主要分成几个部分,比如handlers、porxy、effect、dep。
Handlers
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 === ReactiveFlags.IS_SHALLOW) {
return shallow
} else if (
key === ReactiveFlags.RAW &&
receiver ===
(isReadonly
? shallow
? shallowReadonlyMap
: readonlyMap
: shallow
? shallowReactiveMap
: reactiveMap
).get(target)
) {
return target
}
const targetIsArray = isArray(target)
if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
return Reflect.get(arrayInstrumentations, key, receiver)
}
// 获取值
const res = Reflect.get(target, key, receiver)
if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
return res
}
// 不是只读的收集依赖
if (!isReadonly) {
track(target, TrackOpTypes.GET, key)
}
// 浅层的,直接返回
if (shallow) {
return res
}
// 处理ref
if (isRef(res)) {
// ref unwrapping - does not apply for Array + integer key.
const shouldUnwrap = !targetIsArray || !isIntegerKey(key)
return shouldUnwrap ? res.value : res
}
// 递归观测reactive数据
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res)
}
return res
}
}
function createSetter(shallow = false) {
return function set(
target: object,
key: string | symbol,
value: unknown,
receiver: object
): boolean {
let oldValue = (target as any)[key]
// 如果旧值是只读的,set函数需要返回一个bool值
if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
return false
}
// 处理浅层和ref
if (!shallow && !isReadonly(value)) {
if (!isShallow(value)) {
value = toRaw(value)
oldValue = toRaw(oldValue)
}
if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
oldValue.value = value
return true
}
} else {
}
const hadKey =
isArray(target) && isIntegerKey(key)
? Number(key) < target.length
: hasOwn(target, key)
// 设置reactive对象的值
const result = Reflect.set(target, key, value, receiver)
// 数据已经修改,触发更新, set时trigger, get时track
if (target === toRaw(receiver)) {
if (!hadKey) {
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) {
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
}
return result
}
}
对于深层handlers,在设置和获取时会多一步递归的操作
function get(
target: MapTypes,
key: unknown,
isReadonly = false,
isShallow = false
) {
target = (target as any)[ReactiveFlags.RAW]
const rawTarget = toRaw(target)
const rawKey = toRaw(key)
if (key !== rawKey) {
!isReadonly && track(rawTarget, TrackOpTypes.GET, key)
}
!isReadonly && track(rawTarget, TrackOpTypes.GET, rawKey)
const { has } = getProto(rawTarget)
const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive
if (has.call(rawTarget, key)) {
return wrap(target.get(key))
} else if (has.call(rawTarget, rawKey)) {
return wrap(target.get(rawKey))
} else if (target !== rawTarget) {
target.get(key)
}
}
function set(this: MapTypes, key: unknown, value: unknown) {
value = toRaw(value)
const target = toRaw(this)
const { has, get } = getProto(target)
let hadKey = has.call(target, key)
if (!hadKey) {
key = toRaw(key)
hadKey = has.call(target, key)
} else if (__DEV__) {
checkIdentityKeys(target, has, key)
}
const oldValue = get.call(target, key)
target.set(key, value)
if (!hadKey) {
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) {
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
return this
}
对于深层和浅层的handlers并没有具体实现,而是两种混合在一起,通过不同的工厂函数的参数来决定的,但是在入口函数执行时,会得到具体的handlers来使用
colletionHanlders 主要用于Map,Set,WeakMap,WeakSet
等强类型数据结构, 如果是Array、Object则使用baseHanlders
比如:
export function shallowReactive<T extends object>(
target: T
): ShallowReactive<T> {
return createReactiveObject(
target,
false,
// 工厂函数的生成
shallowReactiveHandlers,
shallowCollectionHandlers,
shallowReactiveMap
)
}
Reactive
reactive函数在响应式流程中相当于,依赖触发的生成者,具体实现是通过不同的handler使用Proxy api代理
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
// if trying to observe a readonly proxy, return the readonly version.
if (isReadonly(target)) {
return target
}
return createReactiveObject(
target,
false,
mutableHandlers,
mutableCollectionHandlers,
reactiveMap
)
}
export function shallowReactive<T extends object>(
target: T
): ShallowReactive<T> {
return createReactiveObject(
target,
false,
shallowReactiveHandlers,
shallowCollectionHandlers,
shallowReactiveMap
)
}
俩个reactive是代理函数,通过不同的handlers由createReactiveObject
生成
Proxy
proxy 是响应式具有代表性的一环,就是通过原生的Proxy api来实现, 这一步做的就是对整个vue用到的状态做数据劫持
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>,
proxyMap: WeakMap<Target, any>
) {
// 目标已经被代理过,直接返回
if (
target[ReactiveFlags.RAW] &&
!(isReadonly && target[ReactiveFlags.IS_REACTIVE])
) {
return target
}
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
// 如果不是reactive支持的数据类型直接返回
/*
// 目前支持的数据类型
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
}
}
*/
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
// 生成代理, 对于set,map使用collectionHanlders
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
// 缓存代理的结果,并返回代理后的对象
proxyMap.set(target, proxy)
return proxy
}
// 对于readonly, 里面最重要的就是这句,不能重新设置
{
set(target, key) {
if (__DEV__) {
console.warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
}
}
Ref
ref可以是一个基本数据类型或者是复杂数据类型
class RefImpl<T> {
private _value: T
private _rawValue: T
// 用于存储当前Ref值的effect, 也就是activeEffect
public dep?: Dep = undefined
public readonly __v_isRef = true
constructor(value: T, public readonly __v_isShallow: boolean) {
this._rawValue = __v_isShallow ? value : toRaw(value)
this._value = __v_isShallow ? value : toReactive(value)
}
get value() {
// 收集依赖,并返回类内部对外不可见的的_value
trackRefValue(this)
return this._value
}
set value(newVal) {
newVal = this.__v_isShallow ? newVal : toRaw(newVal)
// 浅比较,也就是Object.is(), 如果有变化就触发更新
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = this.__v_isShallow ? newVal : toReactive(newVal)
triggerRefValue(this, newVal)
}
}
}
class CustomRefImpl<T> {
public dep?: Dep = undefined
private readonly _get: ReturnType<CustomRefFactory<T>>['get']
private readonly _set: ReturnType<CustomRefFactory<T>>['set']
public readonly __v_isRef = true
constructor(factory: CustomRefFactory<T>) {
// 手动传入的factory
const { get, set } = factory(
() => trackRefValue(this),
() => triggerRefValue(this)
)
this._get = get
this._set = set
}
get value() {
return this._get()
}
set value(newVal) {
this._set(newVal)
}
}
// 关于es6的Geeter、Setter函数
const ref = {
get value() {
},
set value() {
}
};
Effect
export class ReactiveEffect<T = any> {
// active 判断是否可以正常工作的,比如实例调用了stop以后
// active就是false,为false时会直接执行,但不会被触发依赖
active = true
// effect的依赖,key也有依赖,属于双向绑定的依赖
deps: Dep[] = []
// 用于前套effect的处理,之前是stack,现在变成了链表
// stack -> [effetct, effect.parent = prevEffect]
// 在执行完毕回滚时,会调用parent为activeEffect
parent: ReactiveEffect | undefined = undefined
/**
* 于computed的双向绑定
*/
computed?: ComputedRefImpl<T>
allowRecurse?: boolean
onStop?: () => void
// dev only
onTrack?: (event: DebuggerEvent) => void
// dev only
onTrigger?: (event: DebuggerEvent) => void
constructor(
public fn: () => T,
public scheduler: EffectScheduler | null = null,
scope?: EffectScope
) {
// 和scope的绑定
recordEffectScope(this, scope)
}
run() {
if (!this.active) {
return this.fn()
}
// 模拟栈,用于前套, 但activeEffect并不一定是直接上层effect
let parent: ReactiveEffect | undefined = activeEffect
let lastShouldTrack = shouldTrack
// 找到当前执行环境的effect,也就是自身处于链表的位置
while (parent) {
if (parent === this) {
return
}
parent = parent.parent
}
try {
this.parent = activeEffect
activeEffect = this
shouldTrack = true
trackOpBit = 1 << ++effectTrackDepth
// 执行
if (effectTrackDepth <= maxMarkerBits) {
initDepMarkers(this)
} else {
cleanupEffect(this)
}
return this.fn()
} finally {
// 回滚操作
if (effectTrackDepth <= maxMarkerBits) {
finalizeDepMarkers(this)
}
trackOpBit = 1 << --effectTrackDepth
// activeEffect 为当前执行的effect,执行时如果存在副作用
// track时会被收集到map中
activeEffect = this.parent
shouldTrack = lastShouldTrack
this.parent = undefined
}
}
stop() {
if (this.active) {
cleanupEffect(this)
if (this.onStop) {
this.onStop()
}
this.active = false
}
}
}
// ### effectScope
let activeEffectScope: EffectScope | undefined
export class EffectScope {
// 是否可工作
active = true
// 与effect的绑定
effects: ReactiveEffect[] = []
// 监听effectScopoe销毁时的函数数组
cleanups: (() => void)[] = []
// 嵌套使用的链表指针域
parent: EffectScope | undefined
scopes: EffectScope[] | undefined
private index: number | undefined
constructor(detached = false) {
if (!detached && activeEffectScope) {
this.parent = activeEffectScope
this.index =
(activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
this
) - 1
}
}
run<T>(fn: () => T): T | undefined {
if (this.active) {
try {
activeEffectScope = this
return fn()
} finally {
activeEffectScope = this.parent
}
} else if (__DEV__) {
/*
报错。 如果一个作用域已经被停职,再次执行会报错
因为所有的effect已经被停止
比如effect.active为false时,值执行函数,并不会处理依关系
*/
}
}
on() {
// 挂载链表
activeEffectScope = this
}
off() {
// 回滚链表
activeEffectScope = this.parent
}
stop(fromParent?: boolean) {
if (this.active) {
let i, l
for (i = 0, l = this.effects.length; i < l; i++) {
this.effects[i].stop()
}
for (i = 0, l = this.cleanups.length; i < l; i++) {
this.cleanups[i]()
}
if (this.scopes) {
for (i = 0, l = this.scopes.length; i < l; i++) {
this.scopes[i].stop(true)
}
}
// nested scope, dereference from parent to avoid memory leaks
if (this.parent && !fromParent) {
// optimized O(1) removal
const last = this.parent.scopes!.pop()
if (last && last !== this) {
this.parent.scopes![this.index!] = last
last.index = this.index!
}
}
this.active = false
}
}
}
export function recordEffectScope(
effect: ReactiveEffect,
scope: EffectScope | undefined = activeEffectScope
) {
if (scope && scope.active) {
scope.effects.push(effect)
}
}
// effectScope用于多一个effect或者watch一起执行,在条件不允许的情况下
// 也能被正常的销毁
Track、Trigger
type KeyToDepMap = Map<any, Dep>
const targetMap = new WeakMap<any, KeyToDepMap>()
/*
一个应用的依赖
weakMap: {
[target:一个对象] : Map: {
[target.keys()]: Set: [effect]
}
}
*/
export function track(target: object, type: TrackOpTypes, key: unknown) {
// 需要收集,并且,当前effect存在,存在副作用函数
if (shouldTrack && activeEffect) {
// 获取
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = createDep()))
}
const eventInfo = __DEV__
? { effect: activeEffect, target, type, key }
: undefined
// dep -> set<Effect>
trackEffects(dep, eventInfo)
}
}
export function trackEffects(
dep: Dep,
debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
let shouldTrack = false
if (effectTrackDepth <= maxMarkerBits) {
if (!newTracked(dep)) {
dep.n |= trackOpBit // set newly tracked
shouldTrack = !wasTracked(dep)
}
} else {
// 如果依赖项中已经存在活跃的effect,跳过
shouldTrack = !dep.has(activeEffect!)
}
if (shouldTrack) {
// 把活跃的effect,添加到当前获取key的deps中
dep.add(activeEffect!)
// 双向绑定, 在stop时,可以直接从依赖中删除
activeEffect!.deps.push(dep)
if (__DEV__ && activeEffect!.onTrack) {
activeEffect!.onTrack(
Object.assign(
{
effect: activeEffect!
},
debuggerEventExtraInfo
)
)
}
}
}
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) {
// 当前的keyMap没有可以通知的effect
return
}
let deps: (Dep | undefined)[] = []
if (type === TriggerOpTypes.CLEAR) {
// 触发所有dep, set展开
deps = [...depsMap.values()]
} else if (key === 'length' && isArray(target)) {
// 是数组的情况,就把dep:set 加入到deps中,用于触发
depsMap.forEach((dep, key) => {
if (key === 'length' || key >= (newValue as number)) {
deps.push(dep)
}
})
} else {
if (key !== void 0) {
deps.push(depsMap.get(key))
}
// 对于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)
}
}
// 创建一个set,防止重复
if (__DEV__) {
triggerEffects(createDep(effects), eventInfo)
} else {
triggerEffects(createDep(effects))
}
}
}
export function triggerEffects(
dep: Dep | ReactiveEffect[],
debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
// spread into array for stabilization
for (const effect of isArray(dep) ? dep : [...dep]) {
if (effect !== activeEffect || effect.allowRecurse) {
if (__DEV__ && effect.onTrigger) {
effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
}
// computed存在scheduler
if (effect.scheduler) {
effect.scheduler()
} else {
// 如果更新过程中存在副作用,继续使用effect收集
effect.run()
}
}
}
}
总体的一个流程,还是沿用vue2的响应式原理,获取时收集依赖,设置时触发更新,之前的watcher也可以被effect代替
比如实现一个简易的依赖收集系统
let activeEffect = null;
function effect(fn) {
let run = () => fn();
activeEffect = run;
run();
activeEffect = null;
}
let deps = new Set<Function>();
function track() {
if (activeEffect != null) {
deps.add(activeEffect);
}
}
function trigger(newVal, oldValue) {
deps.forEach(effect => effect(newVal, oldValue));
}
function ref(value) {
const ans = {
get value() {
track();
return value;
},
set value(newVal) {
let oldValue = value;
value = newVal;
trigger(newVal, oldValue)
}
};
return ans;
}