写文章不容易,点个赞呗兄弟专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧node
研究基于 Vue版本 【2.5.17】数组
若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧缓存
【Vue原理】Render - 源码版 之 静态 Render 性能优化
上一篇咱们讲了 render 函数,而 Vue 为了更新时速度快一些,加入了一个 staticRender函数
没错,就是 静态 render,看过前面文章的人,应该知道什么是 静态 render性能
静态 render 就是用于渲染哪些不会变化的节点学习
你们能够先看看,Vue 是怎么判断某个节点是不是静态节点优化
Compile 之 optimize 标记静态节点 this
好,下面开始咱们的正文,想了想,咱们仍是以几个问题开始吧 spa
一、静态 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 咱们就讲完了,是否是很简单,在没看源码以前,我觉得很难
如今看完,发现也简单的,不过我也是看了几个月的。。。。
鉴于本人能力有限,不免会有疏漏错误的地方,请你们多多包涵,若是有任何描述不当的地方,欢迎后台联系本人,有重谢