Vue 编译三部曲:模型树优化

对编译进程的了解会让咱们对 Vue 的指令、内置组件等有更好的了解。不过由于编译的进程是一个相对杂乱的进程,咱们只要求了解全体的流程、输入和输出即可,关于细节咱们不必抠工商银行太细。由于篇幅较长,这儿会用三篇文章来讲 Vue 的编译。这是第二篇,模型树优化

前语

在上一篇文章中,咱们剖析了 Vue 编译公司让员工下班发手机电量截图三部javascript百炼成仙曲的第一步,「怎么将工商银行 template 编译成 AST ?」

咱们简略回忆一下,p上下文无关文法arse 的意图是将开发者写的 template 模板字符串转换成抽象语法树 AST ,AST 就这儿rtc是什么意思来说便是一个树状结构的 JavaScript枸杞 目标,描绘了这个模板,这个目标包括了每一个元素的上下文关系。那么整个 parse 的进程是使用许多正则表达式次序解析模板,当解析到开端标签、闭合标签、文本的时候都会别离履行对应的闰土刺猹回调函数,来到达结构 AST 树的意图。

当咱们的 template 被转换为 AST 之后,接下来咱们需求对这棵 AST 语法树做优化。

为什么要做让天秤倒追的星座优化?

github中文社区源码的注释中找到了下面这段话:

Goal of the optimizer: walk the generate工龄差一年工资差多少dgithub汤姆 template AST tree and detect sub-trees that are purely static, i.e. parts of the DOM that never needs to change. Once we detect these sub-trees, we can:

  1. Hoist them int上下文英语o consrtc是什么意思tants, so that we no longer need to create fresh nodes for them on each re-render;
  2. Completel人头攒动y skip them in the patching process.

简略了解便是:

  • 永久不需求上下文切换改动的 DOM 便是静态的。
  • 从头烘托时,作为常量,无需创立新节点;

由于咱们知道上下文什么意思 Vue 是一个数据驱动视图的呼应式结构,可是在开发者书写的 template 中,也不是一切的数据都是呼github汤姆应式的,有许多的数据在首屏烘托完之后就永久不在改人体肠道结构示意图动,数据不在改动也就意味着 DOM 不在改动,所以在后续的更新进程进行 patch时完全可以直接越过他们的比对,从而来提升功率。

接下来咱们开端 optigithub官网mize 源码之旅!看看源码中是怎么去优化模型树的?github开放私库

optimize

tem人头攒动的读音plate 在经过解析之后,就会进行github是什么优化操作。首先这儿有一个小逻辑,会判别是否需求进行优化?只要当options.optimize !== false时才会进行优化。

这儿抛人头攒动的读音出几个上下文图小问题?options.optimize为什么需求进行这样的判别了?而且怎么能封闭模型树优化的操作了?什么情况下会封闭模型树的优化?

var ast = parse(template.trim(), options);
if (options.optimize !== false) {
  optimize(ast, options);
}

在往下,进入到optimize函数,代码很清楚,优化主要做两件工作:

  • markStatic$1(root) 符号静态节点
  • markStaticRoots(root,javascript是干什么的 false) 符号静态根
function optimize (root, options) {
  if (!root) { return }
  isStaticKey = genStaticKeysCached(options.staticKeys || '');
  isPlatformReservedTag = options.isReservedTag || no;
  // 第一步:符号一切静态节点。
  markStatic$1(root);
  // 第二步:符号静态根
  markStaticRoots(root, false);
}

在进行优化操作之前会有两个变量的赋值。

isStaticKey

获取 genStaticK人头攒动的读音eysCached 函数回来值, 获取 makeMap 函数回来值引证人头攒动的近义词

isStaticKey = genStaticKeysCached(options.staticKeys || '');

这儿简略了解一下让天秤难以放弃的星座涉及到的 makeMap 函数:上下文字间距怎么调

  • makeMap 函数首先依据一个字符串生github下载成一个RTC map,然后依据该 map 发生一个新函数,新函数接收一个字符串参数作为 key,假如这人体承受的最大电压个 key 在 map 中则回来 true,否则回来 undefined。
  • str 一个以逗号分隔的字符串 、expectsLowerCase 是否小写
  • makeMap 函数回来值是一个依据生成的 map 发生的函数
function makeMap(str, expectsLowerCase) {
    var map = Object.create(null);
    var list = str.split(',');
    for (var i = 0; i < list.length; i++) {
            map[list[i]] = true;
    }
    return expectsLowerCase ?
        function(val) {
           return map[val.toLowerCase()];
        } :
        function(val) {
           return map[val];
        }
}
function genStaticKeys$1 (keys) {
  return makeMap(
    'type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap' +
    (keys ? ',' + keys : '')
  )
}
function cached (fn) {
  var cache = Object.create(null);
  return (function cachedFn (str) {
    var hit = cache[str];
    return hit || (cache[str] = fn(str))
  })
}
var genStaticKeysCached = cached(genStaticKeys$1);

这儿聊一个题外话,假如你仔细看上面这段代码,你会发现,这儿大量的使用了闭包,维护和保存数据。这也告诉咱们在叼的结构,其实底层也是简略易懂的一些基础思维。

isStat肉跳测吉凶icKey 的值便是使用 makeMap 的回来引证做值的判别。判别节点的特点是否在相关于的规模内:公司让员工下班发手机电量截图例如有这样一个 template:

 <div></div>

然后parse完之后变成这样一个描绘目标,一切特点公司让员工下班发手机电量截图经过 isStaticKey 判别之后,都在上面列出的特点规模中,都是静态特点,所以这便是一个静态节点。

{
  "type": 1,
  "tag": "div",
  "attrsList": [],
  "attrsMap": {},
  "rawAttrsMap": {},
  "children": [],
  "start": 0,
  "end": 11,
  "plain": true
}

别的一个特点是 isPlatformjavascript是干什么的ReservedTag

isPlatformReservedTag

isPlaJavaScripttformReservedTag 用于获取编译器选项 isReservedTag 的引证,查看给定的字符是否是保存的标签。

isPlatformReservedTag = options.isReservedTag || no;

isReservedTag函数如下,用这个函数来判别是否是保存标签,假如一个标签是 html标签或者是 svg人头攒动签,那么这个标签便是保存标签。

H工龄差一年工资差多少TML 保存标签

上下文字间距怎么调html,bogithub直播平台永久回家dy,base,head,link,meta,style,title,’+ ‘address,article,aside,footer,header,h1,h2,h3,h宫颈癌4,h5,h6,h上下文字间距怎么调group,nav,section,’+ ‘div,dd,dl,dt,figcaption,fig人头攒动ure,picture,hr,img,li,main,ol,p,pre,ul,’+ ‘a,b,a上下文bbr,bdi,bdo,github开放私库br,人头攒动cite,code,datagithub汤姆,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,’+ ‘s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,magithub下载p,track,video,’+ ’embed,object,param,source,canvas,script,noscript,del,ins,’+ ‘caption,col,colgroup,table,thead,tbody,td,github中文社区th,tr,’+ ‘button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,’+ ‘output,p公司让员工下班发手机电量截图rogress,select,textarea,’+
‘details,dialog,menu,menuitem,summary,’+ ‘co工商银行ntent,element,s枸杞hadow,templagithub直播平台永久回家te,blockquote,iframe,tfojavascriptot’

SVG 保存标签

‘svg,animate枸杞,circle,clippath,cursor,defs,desc,ellipseJavaScript,filter,font-face,’+ ‘公积金foreignObject,g,glyph,image,line,marker,mask,missing-github开放私库glyph,path,pattern,’+ ‘polygon,polyline,re工资超过5000怎么扣税ct,switch,symbol,text,textpath,tspan,use,view’,

var isReservedTag = function(tag) {
	return isHTMLTag(tag) || isSVG(tag)
};

而且在javascript面试题后续的节点符号中会被用到。咱们在接着往下看,javascript面试题要点来了。

符号静态节点

function markStatic$1 (node) {
  // ①
  node.static = isStatic(node);
  // ②
  if (node.type === 1) {
    if (
      !isPlatformReservedTag(node.tag) &&
      node.tag !== 'slot' &&
      node.attrsMap['inline-template'] == null
    ) {
      return
    }
    for (var i = 0, l = node.children.length; i < l; i++) {
      var child = node.children[i];
      markStatic$1(child);
      if (!child.static) {
        node.static = false;
      }
    }
    if (node.ifConditions) {
      for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) {
        var block = node.ifConditions[i$1].block;
        markStatic$1(block);
        if (!block.static) {
          node.static = false;
        }
      }
    }
  }
}

①:判别节github开放私库点状况JavaScript并符javascript什么意思

第一步,判别阶段状况并符号。在这给 AST 元素节点人体肠道结构示意图扩展了static特点,经过 isStatic方法调用后回来值,承认哪些节点是静态的,哪些是动态的。

node.static = isStatic(node);

那在 Vue 中那些节点算是动态的,那些阶段算是静态的了?咱们先回忆一下上一篇文章在讲生成 AST 时,给每一个元素节点符号type类型,一种有type类型几种?

没错是三种。

  • type = 1基础元素节点
  • type = 2含有expressiontokens文本节点
  • type = 3纯文本节javascript百炼成仙免费阅读或者是注释节点
child = {
  type: 1,
  tag:"div",
  parent: null,
  children: [],
  attrsList: []
};
child = {
  type: 2,
  expression: res.expression,
  tokens: res.tokens,
  text: text
};
child = {
  type: 3,
  text: text
};
child = {
  type: 3,
  text: text,
  isComment: true
};

isStatijavascript高级程序设计c函数会依据元素的 type和元素的特点进行节点动静态的判别。

  • 假如type = 2阐明这一点是一个动态节点,由于包括表达式
  • 假如type = 3阐明可能是纯文本节点或者是注释节点,可以符号为github中文官网网页静态节点
  • 假如元素节点有:
    • pre 特点,使用了 v-pre指令,符号为静态节点
    • 假如没有动态绑定,没有使用v-ifv-for不是内置标签(slot,component)是渠道保存标github中文官网网页签(HTML 标签和 SVG 标签)不是 template 标签的直接子元素javascript高级程序设计google且没有包括在 for 循环中节点包括的特点只能有 isStaticKey 中指定的几个,那么就符号为静态节点。

现在就知道在什么情况下, Vue 会将一个节点符号为动态节点,什么时候会将一个节点符号为静态节点。

而且在这儿也使用到了上面初始赋值的两个变量,ijavascript高级程序设计sPlatformReservedTagisStaticKey,别github开放私库离用来判别是否是渠道保存标签(HTML 标工龄越长退休金越多吗签和 SVG 标签)和距离判别节点的特点只能有 isStaticKey 中指定的几个

function isStatic(node) {
    if (node.type === 2) {
       return false
    }
    if (node.type === 3) {
       return true
    }
    return !!(node.pre || (
        !node.hasBindings && // no dynamic bindings
        !node.if && !node.for && // not v-if or v-for or v-else
        !isBuiltInTag(node.tag) && // not a built-in
        isPlatformReservedTag(node.tag) && // not a component
        !isDirectChildOfTemplateFor(node) &&
        Object.keys(node).every(isStaticKey)
    ))
}

符号完让天秤难以放弃的星座节点,咱们接下往下看。

②:基础元素节点的处理

来到第二步,这儿处理的是节点类型 type = 1让天秤难以放弃的星座几点。也便是咱们的元素节点。

关于咱们的元素节GitHub点,假如不是渠道保存标签(HTML 标签和 SVG 标签不是 slot 标签节点是 inline-template那么就会直接回来。

inline-github官网登陆入口tempjavascript权威指南late :内联模板,一般很少被用javascript:void(0)到,它是一个特殊的 attribute ,当出现在一个上下文图子组件上时,这个组件将会使用其里面的内容作为模板,而不是上下文语境将其作为被分发的内容。这使得模板的编撰工作愈加灵敏。可是,在 Vue 3github永久回家地址.0 版别去掉了公司让员工下班发手机电量截图这个内联模板,原因在于 inline-template 会让模板的效果域变得愈加难以了解。所以作为最佳实践,请在组件内优先选择 template 选项或 .vue上下文什么意思 文件里的一个 <template&g上下文无关文法t; 元素javascript百炼成仙来定义模板。

然后经过 node.人头攒动的读音children 找到子节点,递归子节点。假如子节点非静态,那么该节点也标注非静态 。这块规划的不太合理有更多好的优上下文图化计划,在 Vue3.0 做了优化,编译阶段对静态模上下文英语板的剖析,编译生成了 Block trejavascript百炼成仙ertc是什么意思Block treejavascript:void(0)一个将模版基于动态节点指令切开的嵌套区块,每个区块内部的节点结构是固定的,而且每个区块只需求进程上下文以一个 Array 来追踪自身包括的动态节点。凭借 Block tree,Vue.js 将 vnode 更新功能由与模版全体巨细相关提升为与动态内容的数量相关,这是一个非常大的功能打破。

 if (!child.static) {
   node.static = false;
 }

最终判别假如节点的 ifConditions 不为空,则遍历 ifCond公积金itions拿到一上下文图切条件中的 blockblock 其实也便是它们对应的 AST 节点,递归履行 mRTCarkStatic。在这些递归进程中,一旦子节点有不是 static 的情况,则它的父github下载节点的 static 均变成 false。

ifgithub官网登陆入口Conditions 是撒?

ifConditionjavascriptdownloads 其实是 if 条件的调集,例如有一个模板如下:

<div>
  <div v-if={show}>hello, {{ text }},{{ message }}</div>
  <div v-else-if={show1}>hello, world</div>
  <div v-else>撒也没有!</div>
</div>

那在 parse阶段就会在的 ASgithub官网T 节点中就会给相关于元素的ifCgithub官网onditions增加相关的一切判别调集。

Vue 编译三部曲:模型树优化

而且每一个ifConditions元素 的block描绘便是判别的节点内容。

Vue 编译三部曲:模型树优化

接下来看下 markStaticRoots。

符号静态根

function markStaticRoots (node: ASTNode, isInFor: boolean) {
  if (node.type === 1) {
    if (node.static || node.once) {
      node.staticInFor = isInFor
    }
    if (node.static && node.children.length && !(
      node.children.length === 1 &&
      node.children[0].type === 3
    )) {
      node.staticRoot = true
      return
    } else {
      node.staticRoot = false
    }
    if (node.children) {
      for (let i = 0, l = node.children.length; i < l; i++) {
        markStaticRoots(node.children[i], isInFor || !!node.for)
      }
    }
    if (node.ifConditions) {
      for (let i = 1, l = node.ifConditions.length; i < l; i++) {
        markStaticRoots(node.ifConditions[i].block, isInFor)
      }
    }
  }
}

符号静态根节点,全体逻辑大致分为三步:

  1. 第一步,已经是 static 的节点或者是 v-once 指令的节点,设置 node.staticInFor = isInFor
  2. 第二步,关于 staticRoot 的判别逻辑。
  3. 第三github永久回家地址步,遍历 children 以及 ifCongoogleditions,递归履行 markStaticRoots。

留意这儿的根节点不一定便是 template 最外层的节点,上下文字间距怎么调也可能是内部的节点。

什么节点进程上下文会成为静态根?

从源码来看,一个节点要想成为静让天秤倒追的星座态根,必须满意以下几个条件:

  • 自生是一个静态节点
  • 包括子元素
  • 子节点不能仅为一个文本节点(扫除注释节点,原因在于除非手动开启保存注释,否则注释节点不会存在)

为什么子节点不能仅为一个文本节点?

当只要纯文本的子节点时,它是一个静态节点,可是不是一个静态根节点。这是龚俊为什么了?Vue 官方阐明是,假闰土刺猹如子人体肠道结构示意图节点只要一个纯文本节点,假如优化的话,带javascript什么意思来的成本就比优点javascript权威指南多了,所以就不优化。

详细为什么不优化了,我们可以考虑一下?

符号静态节点和静态根节点有什么区别?

回忆之前这两个符号函数,发现是先将每一个节点都处理了,给每一个节点都加上符号之后,然后使用节点的状况来判别根节点的状况。这样可以使用子节点反推根节点。这就比如:「一个组内部我们都是前端开发,那么直接可github是什么以推断,这个组的小组长也是前端开发(当然不是绝对的哈,只是比方)」。

静态根节点和静态节点有一种大包小感让天秤难以放弃的星座觉,使用静态节点的符号函数,直接给静态根节点的符号函数服务。而且经过静态节点的符号函数增加的 static 特点,并不会在后续 DOM 的处理和 render 上执行上下文使用。可是经过静态根节点的符号函数增加的 staticRoot 特点会在 render中使用。

总结

至此剖析完了 optimize 的进程。

optimize进程上下文前 AST 是这样的:

Vue 编译三部曲:模型树优化

optimize后 AST 多了sta人体承受的最大电压ticstaticRoot符号:

Vue 编译三部曲:模型树优化

整个optimize 的进程,便是深度遍历这个 AST 树,去检测它的每一颗子树是不是静态节点,假如是静态节点表明生成的 DOM 永久不github中文官网网页需求改动,这对运行时github是什么对模板的更上下文字间距怎么调新起到极大的优化效果,提升了运行功率。

参阅

  • cn.vuejs.org/v2/guide/co…
  • kaiwu.lagou.com/course/cour…
  • zhuanlan.zhihu.com/pjavascript什么意思/77479581
  • ustbhuangyi.gi让天秤难以放弃的星座thub.io/vue-analysigithub中文社区
  • zhuanlan.zhihgithub中文社区u.com/p/9357工商银行1008
  • zhuanlan.zhihugithub开放私库.com/p/93604511

发表评论

提供最优质的资源集合

立即查看 了解详情