写文章不容易,点个赞呗兄弟node
专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧数组
研究基于 Vue版本 【2.5.17】缓存
若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧性能优化
【Vue原理】Render - 源码版 之 静态 Render bash
上一篇咱们讲了 render 函数,而 Vue 为了更新时速度快一些,加入了一个 staticRender函数
没错,就是 静态 render,看过前面文章的人,应该知道什么是 静态 render性能
静态 render 就是用于渲染哪些不会变化的节点学习
你们能够先看看,Vue 是怎么判断某个节点是不是静态节点优化
好,下面开始咱们的正文,想了想,咱们仍是以几个问题开始吧
一、静态 render 是什么样子的
二、静态 render 是怎么生成和 保存
三、静态 render 怎么执行
静态 render 其实跟 render 是同样的,都是执行获得 Vnode
只是静态 render,没有绑定动态数据而已,也就是说不会变化
好比说,一个简单 render 是这样的
绑定了动态数据,须要从实例去获取
_c('div',[_v(_s(aa))])
复制代码
而静态 render 是这样的
没有动态数据,这个静态render 的执行结果是永远不会变的
_c('div',[_c('span',[_v("1")])])
复制代码
静态 render 是在 generate 阶段生成的,生成的方式和 render 是同样的
好比在一个模板中,有不少个静态 根节点,像这样
首先,Vue 会在遍历模板的时候,发现 span 和 strong 自己以及其子节点都是静态的
那么就会给 span 和 strong 节点自己设置一个属性 staticRoot,表示他们是静态根节点
而后这两个静态根节点就会生成本身专属的 静态 render
如何标记静态根节点的具体能够看 Compile 之 optimize 标记静态节点
怎么把静态根节点生成 render 的能够看 Compile 之 generate 节点拼接 中 genStatic 的部分
若是你有一直看个人Vue 笔记的话,你应该这里是会有点印象的
以后
静态 render 生成以后是须要保存的,那么保存在哪里呢?
保存在一个数组中,名叫 staticRenderFns,就是直接push 进去
固然了,此时的 push 进去的 静态 render 仍是字符串,并无变成函数
以上面的模板为例,这里的 staticRenderFns 就是这样,包含了两个字符串
staticRenderFns = [
"_c('span',[_c('b',[_v("1")])])",
"_c('strong',[_c('b',[_v("1")])])"
]
复制代码
可是在后面会逐个遍历变成可执行的函数
staticRenderFns = staticRenderFns.map(code => {
return new Function(code)
});
复制代码
那么 这个 staticRenderFns 又是什么啊?
每一个 Vue 实例都有一个独立的 staticRenderFns,用来保存实例自己的静态 render
staticRenderFns 的位置是
vm.$options.staticRenderFns
静态 render 须要配合 render 使用,怎么说
看个例子
这个模板的 render 函数是
_c('div',[
_m(0),
_v(_s(a),
_m(1)
])
复制代码
_m(0) , _m(1) 就是执行的就是 静态 render 函数,而后返回 Vnode
因而 render 也能够完成 vnode 树的构建了
在 Vue 初始化时,给Vue的原型便注册了这个函数,也就是说每一个实例都继承到 _m
function installRenderHelpers(target) {
target._m = renderStatic;
}
installRenderHelpers(Vue.prototype);
复制代码
再来看 renderStatic
function renderStatic(index) {
var cached = this._staticTrees || (this._staticTrees = []);
var tree = cached[index];
// 若是缓存存在,就直接返回
if (tree) return tree
// 这里是执行 render 的地方
tree = cached[index] =
this.$options.staticRenderFns[index].call(
this, null, this
);
// 只是标记静态 和 节点id 而已
markStatic(tree, "__static__" + index, false);
return tree
}
复制代码
这个函数作的事情能够分为几件
一、执行静态render
二、缓存静态render 结果
三、标记 静态 render 执行获得的 Vnode
咱们来一个个说
上面咱们说过了,静态render 保存在 数组 staticRenderFns
因此这个函数接收一个索引值,表示要执行数组内哪一个静态render
取出静态render 后,执行并绑定 Vue 实例为上下文对象
而后获得 Vnode
这一步就是要把上一步获得的 Vnode 缓存起来
那么缓存在哪里呢?
_staticTrees
这是一个数组,每一个实例都会有一个独立的 _staticTrees,用来存在自身的静态 render 执行获得的 Vnode
看一下上个模板中实例保存的 _staticTrees
咱们已经执行静态render获得了 Vnode,这一步目的是标记
标记什么呢
一、添加标志位 isStatic
二、添加 Vnode 惟一id
renderStatic 中咱们看到标记的时候,调用了 markStatic 方法,如今就来看看
function markStatic(
tree, key
) {
if (Array.isArray(tree)) {
for (var i = 0; i < tree.length; i++) {
if ( tree[i] && typeof tree[i] !== 'string') {
var node = tree[i]
node.isStatic = true;
node.key = key + "_" + i;
}
}
}
else {
tree.isStatic = true;
tree.key = key
}
}
复制代码
前面咱们添加的全部静态标志位都是针对 模板生成的 ast
这里咱们是给 Vnode 添加 isStatic,这才能完成Vue的目的
Vue 目的就是性能优化,在页面改变时,能尽可能少的更新节点
因而在页面变化时,当 Vue 检测到该 Vnode.isStatic = true,便不会比较这部份内容
从而减小比对时间
每一个静态根Vnode 都会存在的一个属性
我也没想到 静态Vnode 的 key 有什么做用,毕竟不须要比较,也许是易于区分??
静态 render 咱们就讲完了,是否是很简单,在没看源码以前,我觉得很难
如今看完,发现也简单的,不过我也是看了几个月的。。。。
鉴于本人能力有限,不免会有疏漏错误的地方,请你们多多包涵,若是有任何描述不当的地方,欢迎后台联系本人,有重谢