Skip to content

Commit f09d4ba

Browse files
committed
看完reactivity所有源码,添加部分注释
1 parent ca70aff commit f09d4ba

File tree

3 files changed

+73
-33
lines changed

3 files changed

+73
-33
lines changed

packages/reactivity/src/baseHandlers.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { LOCKED } from './lock'
55
import { isObject, hasOwn } from '@vue/shared'
66
import { isRef } from './ref'
77

8+
//Symbol上的可枚举和不可枚举的属性
89
const builtInSymbols = new Set(
910
Object.getOwnPropertyNames(Symbol)
1011
.map(key => (Symbol as any)[key])
@@ -13,14 +14,18 @@ const builtInSymbols = new Set(
1314

1415
function createGetter(isReadonly: boolean) {
1516
return function get(target: any, key: string | symbol, receiver: any) {
16-
const res = Reflect.get(target, key, receiver)
17+
const res = Reflect.get(target, key, receiver) //拿到需要的值
18+
//如果是symbol类型,且是Symbol上的属性值,直接返回,不收集依赖
1719
if (typeof key === 'symbol' && builtInSymbols.has(key)) {
1820
return res
1921
}
22+
//如果已经使用ref包装过,直接返回res.value(调用value已经将当前依赖收集到ref包装后的对象里)
2023
if (isRef(res)) {
2124
return res.value
2225
}
26+
//依赖收集
2327
track(target, OperationTypes.GET, key)
28+
//返回的值是对象的话,对值也进行监听。
2429
return isObject(res)
2530
? isReadonly
2631
? // need to lazy access readonly and reactive here to avoid
@@ -37,17 +42,24 @@ function set(
3742
value: any,
3843
receiver: any
3944
): boolean {
45+
//格式化值,主要是判断这个值是不是已经相应式的。
4046
value = toRaw(value)
41-
const hadKey = hasOwn(target, key)
42-
const oldValue = target[key]
47+
const hadKey = hasOwn(target, key) //赋值的key是否存在
48+
const oldValue = target[key] //旧的值
49+
//这里的逻辑:
50+
//记得之前get里面,我们判断,值是ref包装的就直接返回,不进行收集依赖。所以obj.a=ref(1)。我们读取key值a
51+
//的时候,依赖是没有被收集的,依赖只被收集到ref(1)中。当我们重新赋值obj.a=1的时候,因为key值为a的依赖没有收集
52+
//所以无法更新,下面这个逻辑就是判断这种情况。然后强制给ref(1)重新赋值,触发set,依赖更新。说实话,我觉着这样处理很不好
53+
//因为我们强制更新ref(1),其他地方使用这个ref。那么也会被强制更新。
4354
if (isRef(oldValue) && !isRef(value)) {
4455
oldValue.value = value
4556
return true
4657
}
58+
//赋值
4759
const result = Reflect.set(target, key, value, receiver)
48-
// don't trigger if target is something up in the prototype chain of original
60+
//正常来说receiver恒等于target,除非手动改receiver,但是我没发现源码什么地方可以改receiver
4961
if (target === toRaw(receiver)) {
50-
/* istanbul ignore else */
62+
//开发环境记录的信息,追踪用
5163
if (__DEV__) {
5264
const extraInfo = { oldValue, newValue: value }
5365
if (!hadKey) {
@@ -56,6 +68,7 @@ function set(
5668
trigger(target, OperationTypes.SET, key, extraInfo)
5769
}
5870
} else {
71+
//之前存在属性的话类型就是set,不存在的话类型就是add,下面我们看这两个上面区别
5972
if (!hadKey) {
6073
trigger(target, OperationTypes.ADD, key)
6174
} else if (value !== oldValue) {

packages/reactivity/src/effect.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,25 +118,38 @@ export function track(
118118
type: OperationTypes,
119119
key?: string | symbol
120120
) {
121+
//全局的一个锁控制是否依赖收集
121122
if (!shouldTrack) {
122123
return
123124
}
125+
//当前活动的effect,类似于老版本的watcher, render就是一个watcher,这里render,computed等都是effect
124126
const effect = activeReactiveEffectStack[activeReactiveEffectStack.length - 1]
125127
if (effect) {
128+
//这个只有当调用的是set和map等特殊数据结构的'keys', 'values', 'entries‘等方法时候,type才会为iterate。
129+
//其实我们所有依赖的储存都是map的形式。key是你get的key,value就是依赖数组,比如你读obj.a 那么key就是a,value就是
130+
//所有读obj.a的依赖,按理我们调用keys,values,entries等的时候 key应该是不同的值,但是事实上这些key对应的依赖都应该
131+
//是同步更新,也就是说调用keys的依赖更新,调用values的依赖也必须更新。所以这里将他们都拿一个值存储
132+
//这里的type一般是add,del等等,当调用'keys', 'values', 'entries‘的时候是iterate
126133
if (type === OperationTypes.ITERATE) {
127134
key = ITERATE_KEY
128135
}
136+
//targetMap存储的key是对象,value也是一个map,下面会解释这个map上面东西
129137
let depsMap = targetMap.get(target)
138+
//没有的话,新建一个map
130139
if (depsMap === void 0) {
131140
targetMap.set(target, (depsMap = new Map()))
132141
}
142+
//depsmap的key是调用的key值,value是一个set。储存所有的依赖,
133143
let dep = depsMap.get(key as string | symbol)
144+
//没有的话,新建一个set,所以就算访问不存在的属性,也会将依赖收集。
134145
if (!dep) {
135146
depsMap.set(key as string | symbol, (dep = new Set()))
136147
}
148+
//收集依赖。
137149
if (!dep.has(effect)) {
138-
dep.add(effect)
139-
effect.deps.push(dep)
150+
dep.add(effect) //这里是依赖收集
151+
effect.deps.push(dep) //因为依赖也有个deps数组,将当前属性值所有的依赖存入正在收集的依赖中。computed的时候要用,到时会就懂为什么这里收集
152+
//开发环境追踪,
140153
if (__DEV__ && effect.onTrack) {
141154
effect.onTrack({
142155
effect,
@@ -155,34 +168,40 @@ export function trigger(
155168
key?: string | symbol,
156169
extraInfo?: any
157170
) {
171+
//拿到target的所有的依赖map(key是对象的各个属性,value是依赖)
158172
const depsMap = targetMap.get(target)
159173
if (depsMap === void 0) {
160174
// never been tracked
161175
return
162176
}
177+
//储存一般的effect
163178
const effects: Set<ReactiveEffect> = new Set()
179+
//储存computed生成的effect
164180
const computedRunners: Set<ReactiveEffect> = new Set()
181+
//当type为clear时候,所有属性的依赖都要更新,因为所有属性都被清空
165182
if (type === OperationTypes.CLEAR) {
166-
// collection being cleared, trigger all effects for target
167183
depsMap.forEach(dep => {
184+
//添加依赖
168185
addRunners(effects, computedRunners, dep)
169186
})
170187
} else {
171-
// schedule runs for SET | ADD | DELETE
188+
//添加依赖
172189
if (key !== void 0) {
173190
addRunners(effects, computedRunners, depsMap.get(key as string | symbol))
174191
}
175-
// also run for iteration key on ADD | DELETE
192+
//当数组的时候触发更新, add和delete都会引起length的变化,所以判断是数组且更新类型是add和delete的时候,额外更新调用了属性lengrh的依赖。
193+
//当不为数组且是add或者delete的时候,更新key为iterate的依赖,这时候有可能是set和map等特殊类型,因为更新类型是add和delete的时候。
194+
//他们的size,keys等等属性的依赖都需要跟着变化
176195
if (type === OperationTypes.ADD || type === OperationTypes.DELETE) {
177196
const iterationKey = Array.isArray(target) ? 'length' : ITERATE_KEY
178197
addRunners(effects, computedRunners, depsMap.get(iterationKey))
179198
}
180199
}
200+
//运行依赖
181201
const run = (effect: ReactiveEffect) => {
182202
scheduleRun(effect, target, type, key, extraInfo)
183203
}
184-
// Important: computed effects must be run first so that computed getters
185-
// can be invalidated before any normal effects that depend on them are run.
204+
//注意这里先运行computed生成的依赖,然后在运行普通的依赖,因为普通的依赖有可能需要读取computed的新值
186205
computedRunners.forEach(run)
187206
effects.forEach(run)
188207
}
@@ -203,6 +222,7 @@ function addRunners(
203222
}
204223
}
205224

225+
//批量更新依赖
206226
function scheduleRun(
207227
effect: ReactiveEffect,
208228
target: any,
@@ -223,6 +243,7 @@ function scheduleRun(
223243
)
224244
)
225245
}
246+
226247
if (effect.scheduler !== void 0) {
227248
effect.scheduler(effect)
228249
} else {

packages/reactivity/src/index.ts

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
1-
export { ref, isRef, toRefs, Ref, UnwrapRef } from './ref'
21
export {
3-
reactive,
4-
isReactive,
5-
readonly,
6-
isReadonly,
7-
toRaw,
8-
markReadonly,
9-
markNonReactive
2+
ref, //ref api
3+
isRef, //判断是否是已经使用ref包装过的数据
4+
toRefs, //传入对象。将对象中的值都使用ref包装一层
5+
Ref, //ref的ts类型
6+
UnwrapRef //没有被ref包装的ts类型
7+
} from './ref'
8+
export {
9+
reactive, //reactive api
10+
isReactive, //判断是否reactive包装过一层
11+
readonly, //readonly api,和reactive大体一致,但是这个包装的对象是可读的。其实可以赋值。使用下面的unlock
12+
isReadonly, //判断是否是readonly包装过一层
13+
toRaw, //object和使用reactive包装过后的object1 有一个隐射关系(使用map),调用这个函数可以根据object1得到object
14+
markReadonly, //调用这个函数,作用是将参数加入readonly名单,然后你使用reactive api包装对象时候的时候,自动判断在不在黑名单,在黑名单的话会调用readonly
15+
markNonReactive //调用这个函数,将参数加入名单。使用reactive api的时候自动判断要包装的对象在不在名单。不在的话禁止包装,返回原对象
1016
} from './reactive'
1117
export {
12-
computed,
13-
ComputedRef,
14-
WritableComputedRef,
15-
WritableComputedOptions
18+
computed, // computed api
19+
ComputedRef, //computed返回的是一个readonly ref对象,正常compoted返回的ts类型
20+
WritableComputedRef, //当computed自行定义get和set的时候,返回的值是可写的,可写的ref ts类型
21+
WritableComputedOptions //自定义get和set的computed 传入的参数的ts 类型
1622
} from './computed'
1723
export {
18-
effect,
19-
stop,
20-
pauseTracking,
21-
resumeTracking,
22-
ITERATE_KEY,
23-
ReactiveEffect,
24-
ReactiveEffectOptions,
24+
effect, //effect api
25+
stop, //effect所依赖的对象停止自动更新effect。将有关effect的依赖清楚
26+
pauseTracking, //停止目前所有的依赖收集
27+
resumeTracking, //恢复依赖收集
28+
ITERATE_KEY, //一个Symbol类型的值,依赖更新时候的一种类型
29+
ReactiveEffect, //effect的类型。类似于vue2的watcher。依赖的类型
30+
ReactiveEffectOptions, //调用effect的传参
2531
DebuggerEvent
2632
} from './effect'
27-
export { lock, unlock } from './lock'
28-
export { OperationTypes } from './operations'
33+
export { lock, unlock } from './lock' //加锁解锁是否可以修改可读类型
34+
export { OperationTypes } from './operations' //数据更新的类型。add/delete等等

0 commit comments

Comments
 (0)