Skip to content

Commit 8e57089

Browse files
committed
[update] 更新代码注释
1 parent ceac1f7 commit 8e57089

File tree

8 files changed

+90
-25
lines changed

8 files changed

+90
-25
lines changed

vue/src/core/global-api/extend.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,26 @@ export function initExtend (Vue: GlobalAPI) {
1919
// 构造一个 Vue 的子类
2020
Vue.extend = function (extendOptions: Object): Function {
2121
extendOptions = extendOptions || {}
22+
23+
// this 指向 Vue
2224
const Super = this
2325
const SuperId = Super.cid
26+
27+
// 优化点:将构造器缓存起来,下次再实例直接返回
2428
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
2529
if (cachedCtors[SuperId]) {
2630
return cachedCtors[SuperId]
2731
}
2832

2933
const name = extendOptions.name || Super.options.name
3034
if (process.env.NODE_ENV !== 'production' && name) {
35+
36+
// 校验组件名称:1.不允许是内置标签;2.只能英文开头
3137
validateComponentName(name)
3238
}
3339

3440
// 原型继承
41+
// 声明子类构造器
3542
const Sub = function VueComponent (options) {
3643
this._init(options)
3744
}

vue/src/core/instance/lifecycle.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,12 @@ export function lifecycleMixin (Vue: Class<Component>) {
5858
const prevVnode = vm._vnode
5959
const prevActiveInstance = activeInstance
6060
activeInstance = vm
61+
62+
// 将虚拟node缓存在_vnode
6163
vm._vnode = vnode
6264
// Vue.prototype.__patch__ is injected in entry points
6365
// based on the rendering backend used.
66+
// 首次渲染没有对比VNode,这里为null
6467
if (!prevVnode) {
6568
// initial render
6669
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)

vue/src/core/instance/state.js

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ function initData (vm: Component) {
135135
)
136136
}
137137
// proxy data on instance
138+
// 判断data的key值有没跟props和methods一样的,有的话发出警告
138139
const keys = Object.keys(data)
139140
const props = vm.$options.props
140141
const methods = vm.$options.methods
@@ -155,6 +156,9 @@ function initData (vm: Component) {
155156
`Use prop default value instead.`,
156157
vm
157158
)
159+
160+
// 判断key的首字符是不是 $ 或 _
161+
// 不是将属性代理到 vue 实例中
158162
} else if (!isReserved(key)) {
159163

160164
// 代理到实例下面
@@ -184,10 +188,12 @@ const computedWatcherOptions = { computed: true }
184188
// 定义computed属性
185189
function initComputed (vm: Component, computed: Object) {
186190
// $flow-disable-line
191+
// 创建一个空对象
187192
const watchers = vm._computedWatchers = Object.create(null)
188193
// computed properties are just getters during SSR
189194
const isSSR = isServerRendering()
190195

196+
// 遍历拿到每个用户定义的computed getter
191197
for (const key in computed) {
192198
const userDef = computed[key]
193199
const getter = typeof userDef === 'function' ? userDef : userDef.get
@@ -200,23 +206,7 @@ function initComputed (vm: Component, computed: Object) {
200206

201207
if (!isSSR) {
202208
// create internal watcher for the computed property.
203-
/**
204-
* 熟悉的new Watcher,创建一个订阅者,为了之后收集依赖
205-
* 将例子中的num、lastNum和计算属性comNum进行绑定
206-
* 也就是说在一个deps中有两个dep,其中的subs分别是
207-
* dep1.subs:[watcher(num),watcher(comNum)]
208-
* dep2.subs:[watcher(lastNum),watcher(comNum)]
209-
* dep3........
210-
* 请看前面的例子,页面html中并没有渲染{{lastNum}};按理说就不会执行lastNum的getter
211-
* 从而就不会和计算属性进行关联绑定,如果更改lastNum就不会触发dep2的notify()发布
212-
* 自然也就不会在页面看到comNum有所变化,但是运行后却不是这样,为什么呢
213-
* 这就引出这个initComputed的下面方法了---依赖收集(watcher.prototype.depend)!
214-
* 当时也是看了好久才知道这个depend方法的作用,后面再说
215-
* 首先先来提个头,就是下面代码中watcher中这个getter
216-
* 其实就是function comNum() {return this.num+"-computed-"+this.lastNum;}}
217-
* 而这个getter什么时候执行呢,会在Watcher.prototype.evaluate()方法中执行
218-
* 所以watcher中的evaluate()与depend()两个方法都与initComputed相关
219-
*/
209+
// 为每一个 getter 创建一个 computed watcher
220210
watchers[key] = new Watcher(
221211
vm,
222212
getter || noop,

vue/src/core/observer/dep.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ let uid = 0
1111
*/
1212
// 收集依赖对象
1313
export default class Dep {
14-
static target: ?Watcher;
14+
static target: ?Watcher; // 静态属性 target,这是一个全局唯一 Watcher
1515
id: number;
1616
subs: Array<Watcher>;
1717

1818
constructor () {
1919
this.id = uid++
20+
21+
// 用于收集订阅对象
2022
this.subs = []
2123
}
2224

@@ -50,6 +52,8 @@ Dep.target = null
5052
const targetStack = []
5153

5254
export function pushTarget (_target: ?Watcher) {
55+
56+
// Dep.target 赋值为当前的渲染 watcher 并压栈(为了恢复用)
5357
if (Dep.target) targetStack.push(Dep.target)
5458
Dep.target = _target
5559
}

vue/src/core/observer/index.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,13 @@ export class Observer {
4141

4242
constructor (value: any) {
4343
this.value = value
44+
45+
// 实例化一个 Dep 对象
4446
this.dep = new Dep()
4547
this.vmCount = 0
48+
49+
// 把自身实例添加到数据对象 value 的 __ob__ 属性上
50+
// 定义在 src/core/util/lang.js
4651
def(value, '__ob__', this)
4752
if (Array.isArray(value)) {
4853
const augment = hasProto
@@ -60,6 +65,7 @@ export class Observer {
6065
* getter/setters. This method should only be called when
6166
* value type is Object.
6267
*/
68+
// 将每个属性转换成 getter/setter,注意函数参数是对象
6369
walk (obj: Object) {
6470
const keys = Object.keys(obj)
6571
for (let i = 0; i < keys.length; i++) {
@@ -71,6 +77,8 @@ export class Observer {
7177
* Observe a list of Array items.
7278
*/
7379
observeArray (items: Array<any>) {
80+
81+
// 遍历数组再次调用 observe
7482
for (let i = 0, l = items.length; i < l; i++) {
7583
observe(items[i])
7684
}
@@ -114,17 +122,17 @@ export function observe (value: any, asRootData: ?boolean): Observer | void {
114122
}
115123
let ob: Observer | void
116124

117-
// 如果有ob,就直接返回
125+
// 如果有ob,说明已经是个响应式对象,就直接返回
118126
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
119127
ob = value.__ob__
120128

121129
// 没有的话实例一个ob对象
122130
} else if (
123-
shouldObserve &&
124-
!isServerRendering() &&
125-
(Array.isArray(value) || isPlainObject(value)) &&
126-
Object.isExtensible(value) &&
127-
!value._isVue
131+
shouldObserve && // 定义的变量,true,在initProps会改变该值
132+
!isServerRendering() && // 服务端渲染
133+
(Array.isArray(value) || isPlainObject(value)) && // 数组或纯对象
134+
Object.isExtensible(value) && // 可扩展
135+
!value._isVue // 不是 vue 实例
128136
) {
129137
ob = new Observer(value)
130138
}
@@ -148,7 +156,10 @@ export function defineReactive (
148156
/*在闭包内存储一个Dep对象*/
149157
const dep = new Dep()
150158

159+
// 拿到 obj 的属性描述符
151160
const property = Object.getOwnPropertyDescriptor(obj, key)
161+
162+
// 判断,如果是不能配置的属性,直接终止程序
152163
if (property && property.configurable === false) {
153164
return
154165
}
@@ -160,14 +171,16 @@ export function defineReactive (
160171
val = obj[key]
161172
}
162173

174+
// 对子对象递归调用 observe 方法,这样就保证了无论 obj 的结构多复杂,它的所有子属性也能变成响应式的对象
163175
let childOb = !shallow && observe(val)
164176
Object.defineProperty(obj, key, {
165177
enumerable: true,
166178
configurable: true,
167179
get: function reactiveGetter () {
168-
// 依赖收集
169180
const value = getter ? getter.call(obj) : val
170181
if (Dep.target) {
182+
183+
// 依赖收集
171184
dep.depend()
172185
if (childOb) {
173186
childOb.dep.depend()
@@ -193,6 +206,8 @@ export function defineReactive (
193206
} else {
194207
val = newVal
195208
}
209+
210+
// shallow 为 false 的情况,会对新设置的值变成一个响应式对象
196211
childOb = !shallow && observe(newVal)
197212
// 通知订阅者
198213
dep.notify()
@@ -205,6 +220,7 @@ export function defineReactive (
205220
* triggers change notification if the property doesn't
206221
* already exist.
207222
*/
223+
// 当需要给对象添加新属性并触发页面改变时,可以调用set函数
208224
export function set (target: Array<any> | Object, key: any, val: any): any {
209225
if (process.env.NODE_ENV !== 'production' &&
210226
(isUndef(target) || isPrimitive(target))

vue/src/core/observer/scheduler.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,17 @@ function flushSchedulerQueue () {
4747
// user watchers are created before the render watcher)
4848
// 3. If a component is destroyed during a parent component's watcher run,
4949
// its watchers can be skipped.
50+
51+
/**
52+
* 1.组件的更新由父到子;因为父组件的创建过程是先于子的,所以 watcher 的创建也是先父后子,执行顺序也应该保持先父后子。
53+
* 2.用户的自定义 watcher 要优先于渲染 watcher 执行;因为用户自定义 watcher 是在渲染 watcher 之前创建的。
54+
* 3.如果一个组件在父组件的 watcher 执行期间被销毁,那么它对应的 watcher 执行都可以被跳过,所以父组件的 watcher 应该先执行。
55+
*/
5056
queue.sort((a, b) => a.id - b.id)
5157

5258
// do not cache length because more watchers might be pushed
5359
// as we run existing watchers
60+
// 这里不缓存队列长度的原因是在 watcher.run() 的时候,很可能用户会再次添加新的 watcher
5461
for (index = 0; index < queue.length; index++) {
5562
watcher = queue[index]
5663
if (watcher.before) {
@@ -129,6 +136,8 @@ function callActivatedHooks (queue) {
129136
*/
130137
export function queueWatcher (watcher: Watcher) {
131138
const id = watcher.id
139+
140+
// 确保只会push一次
132141
if (has[id] == null) {
133142
has[id] = true
134143
if (!flushing) {
@@ -143,6 +152,8 @@ export function queueWatcher (watcher: Watcher) {
143152
queue.splice(i + 1, 0, watcher)
144153
}
145154
// queue the flush
155+
156+
// 保证只执行一次nextTick
146157
if (!waiting) {
147158
waiting = true
148159
nextTick(flushSchedulerQueue)

vue/src/core/observer/watcher.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ let uid = 0
2222
* and fires callback when the expression value changes.
2323
* This is used for both the $watch() api and directives.
2424
*/
25+
26+
/* new Watcher(vm, updateComponent, noop, {
27+
before () {
28+
if (vm._isMounted) {
29+
callHook(vm, 'beforeUpdate')
30+
}
31+
}
32+
}, true) */
2533
export default class Watcher {
2634
vm: Component;
2735
expression: string;
@@ -68,15 +76,23 @@ export default class Watcher {
6876
this.id = ++uid // uid for batching
6977
this.active = true
7078
this.dirty = this.computed // for computed watchers
79+
80+
// 跟dep相关的一些属性
81+
// 表示 Watcher 实例持有的 Dep 实例的数组
7182
this.deps = []
7283
this.newDeps = []
84+
85+
// 代表 this.deps 和 this.newDeps 的 id Set
7386
this.depIds = new Set()
7487
this.newDepIds = new Set()
88+
7589
this.expression = process.env.NODE_ENV !== 'production'
7690
? expOrFn.toString()
7791
: ''
7892
// parse expression for getter
7993
if (typeof expOrFn === 'function') {
94+
95+
// 这里的getter是updateComponent函数
8096
this.getter = expOrFn
8197
} else {
8298
this.getter = parsePath(expOrFn)
@@ -90,10 +106,14 @@ export default class Watcher {
90106
)
91107
}
92108
}
109+
110+
// computed watcher并不会立刻求值
93111
if (this.computed) {
94112
this.value = undefined
95113
this.dep = new Dep()
96114
} else {
115+
116+
// 执行watch的get函数
97117
this.value = this.get()
98118
}
99119
}
@@ -106,6 +126,8 @@ export default class Watcher {
106126
let value
107127
const vm = this.vm
108128
try {
129+
130+
// this.getter 对应就是 updateComponent 函数
109131
value = this.getter.call(vm, vm)
110132
} catch (e) {
111133
if (this.user) {
@@ -131,6 +153,9 @@ export default class Watcher {
131153
addDep (dep: Dep) {
132154
const id = dep.id
133155
if (!this.newDepIds.has(id)) {
156+
157+
// 把当前的 watcher 订阅到这个数据持有的 dep 的 subs 中
158+
// 这个目的是为后续数据变化时候能通知到哪些 subs 做准备
134159
this.newDepIds.add(id)
135160
this.newDeps.push(dep)
136161
if (!this.depIds.has(id)) {
@@ -217,6 +242,8 @@ export default class Watcher {
217242
this.dirty = false
218243
if (this.user) {
219244
try {
245+
246+
// 这就是为什么我们写watch时能拿到新值和旧值
220247
cb.call(this.vm, value, oldValue)
221248
} catch (e) {
222249
handleError(e, this.vm, `callback for watcher "${this.expression}"`)

vue/src/core/util/next-tick.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ function flushCallbacks () {
2525
// when state is changed right before repaint (e.g. #6813, out-in transitions).
2626
// Here we use microtask by default, but expose a way to force (macro) task when
2727
// needed (e.g. in event handlers attached by v-on).
28+
29+
// 定义宏任务和微任务
2830
let microTimerFunc
2931
let macroTimerFunc
3032
let useMacroTask = false
@@ -34,6 +36,8 @@ let useMacroTask = false
3436
// in IE. The only polyfill that consistently queues the callback after all DOM
3537
// events triggered in the same loop is by using MessageChannel.
3638
/* istanbul ignore if */
39+
40+
// 宏任务和微任务函数的实现
3741
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
3842
macroTimerFunc = () => {
3943
setImmediate(flushCallbacks)
@@ -78,6 +82,7 @@ if (typeof Promise !== 'undefined' && isNative(Promise)) {
7882
* Wrap a function so that if any code inside triggers state change,
7983
* the changes are queued using a (macro) task instead of a microtask.
8084
*/
85+
// 确保函数执行过程中对数据任意的修改,触发变化执行 nextTick 的时候强制走 macroTimerFunc
8186
export function withMacroTask (fn: Function): Function {
8287
return fn._withTask || (fn._withTask = function () {
8388
useMacroTask = true
@@ -109,6 +114,8 @@ export function nextTick (cb?: Function, ctx?: Object) {
109114
}
110115
}
111116
// $flow-disable-line
117+
118+
// 不传cb直接返回一个promise的调用
112119
if (!cb && typeof Promise !== 'undefined') {
113120
return new Promise(resolve => {
114121
_resolve = resolve

0 commit comments

Comments
 (0)