编译器原理
我们运行app之前执行编译操作
compile => render()
得到的渲染函数会在两种情况下h执行;
- 挂载时候
mount => render() => vnode(得到虚拟dom,想要变成真实dom需要执行 ) => patch(null,n2) => 最后得到dom
在初始化的过程中,我们做了数据的响应式和依赖收集,当我们的数据发生变化的时候会触发和依赖相关的函数,componentEffect,就是用来做依赖收集的函数,数据只要发生变化内部重新执行render函数
init => 数据响应式+依赖收集 => componentEffect()
- Update的时候
componentEffect() => render() => vnode => patch(n1,n2) => dom
在更新的流程中,我门会再次执行render函数,生成vnode => patch(n1,n2) => 最后尝试更新dom
编译器执行的时刻是什么?
在webpack环境下,vue-loader能够.vue文件提前转换,过程中会将template预编译,所以运行时在项目打包时,这种情况运行时不需要编译器,vue.rentime.js,这时候不允许字符串模版,即template
而vue.global.js携带编译器,它会在程序运行时,去提前编译组件模版,这时候不会预编译;
AST(抽象语法数)
AST和Vnode特别像,也是js对象,但是最终产出的结果不一样,AST最终产出的结果是代码,也就是render函数, 而vode是始终伴随生命周期,最终生成dom节点。
解析步骤:
一:parse()
=>ast
解析字符串template为抽象语法树ast
步骤二:transform() 转换
ast深加工, 最终生成的还是ast , 是对挂载的方法和属性进行精细的加工,解析属性、样式、指令等
步骤三: generate() generate函数最后生成的script string 由new Function(‘function render()’) 来生成render函数生成render代码的过程
vue3编译器的优化策略
1:静态节点提升
静态不变的节点,直接把它创建了,放在渲染函数的外部,直接使用,不需要频繁创建了;
2补丁标记和动态属性记录
添加动态补丁
<p :title=“foo”>hello world</p> 对title做动态变化的标记,等之后做diff对比的时候,只做当前的动态值做比对,减少递归遍历的过程。
3缓存事件处理程序
对事件进行缓存,尝试从缓存中获取,render函数执行的时候,不会再重新创建;
4块block
<div id=‘app’> <div> <div></div></div> <span>{{msg}}</span></div>
对块级中只有一个动态的变量进行创建,等执行更新的时候,会定向的对区块儿中的动态元素单独更新。
Vue3虚拟dom和patch算法
vue3对vnode结构做了调整以适应编译器的优化策略,相对应的patch算法也会利用这些变化提高运行速度;
vue3异步更新策略
vue3中也有一套异步更新策略