初始化之后调用$mount会挂载组件编译template
编译
compile编译可以分成parse,optimize与generate三个阶段,最终得到render function
parse
parse 会用正则等方式循环切割字符串,解析template模板中的指令,class,style等数据,形成AST
optimize
标记static静态结点,这是编译过程的一处优化
generate
将AST转化成render function字符串的过程,得到的结果是render的字符串以及staticRenderFns
当render function 被调用的时候,因为会读取所需对象的值,所以会触发getter函数进行【依赖收集】
【依赖收集】的目的是将观察者Watcher对象存放到当前闭包中的订阅者Dep的subs中
在修改对象的值的时候,会触发对应的setter,setter通知之前【依赖收集】得到的Dep中的每一个Watcher
告诉他们自己的值改变了,需要重新渲染视图1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43Vue.prototype.$mount = function(){
//挂在组件 已生成渲染函数,被调用
return mountComponent(this,el,hydrating)
}
//缓存 mount
var mount = Vue.prototype.$mount;
//重新覆盖 编译的功能
Vue,prototype.$mount = function(){
//挂在组件 生成render function
return mount.call(this,el)
}
编译过程:字符串模板转成渲染函数
运行时:调用渲染函数
独立构建 = 编译+运行时
运行时构建 = 运行时
//模板的编译 分成parse,optimize与generate三个阶段,最终得到render function
compileToFunctions(template)
//render function生成通过new Function,可以将函数功能通过字符串传递进去生成新函数
var render = new Function(参数,函数主体内容字符串)
其中函数主体字符串的功能就是返回parse生成的抽象语法树AST
渲染函数在哪被调用
mountComponen(){
//模板编译完成,实例挂载之前调用生命周期函数
callHook(vm,'beforeMount')
初始化 updateComponent函数
在非生产环境下config.performance为true,
初始化 updateComponent时有进行性能追踪的相关代码
(进行性能追踪4个场景:
组件【初始化】时
【编译】时模板转渲染函数时
通过【渲染】函数生成虚拟DOM时
【打补丁】,虚拟DOM转真实Dom时)
vm.update(vm._render(),hydrating)
vm._render() === vm.$options.render() //生成虚拟节点vnode
vm.update() 把vm._render()生成的虚拟节点渲染成真实的DOM
updateComponent 用作参数生成Watcher,即数据发生变化时,可以重新渲染DOM节点
}
vm.$option.render 渲染函数生成
1.生成
vm.$option.render = render 构造器函数调用parse,generate生成函数主体字符串,
再调用new Function返回函数
2.探究渲染函数this指向
initProxy
【渲染函数的作用域代理】
Proxy在目标对象之前架设一层拦截,拦截啥?
读取get;设置set;key in proxyObject 属性检测;with(){}
对一个new Proxy生成的对象进行上述操作时就会引发has钩子函数
vnode = render.call(vm._renderProxy,vm.$creatElement)1
2
3
4
5(function anonymous(){//一个渲染函数
//vm.renderProxy 访问变量A就会进行拦截
//调用proxy的has钩子函数 ,钩子函数中进行依赖收集,与生成的watcher进行绑定
with(this){return ...变量A...}
})
vue 对象生成
1 | //vue 对象生成 |