最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue源码解析系列(七) -- 模板tamplate在解析的时候做了哪些优化

    正文概述 掘金(一溪之石)   2020-12-08   462

    上一章Vue源码解析系列(六) -- 模板tamplate是如何解析编译的我们讲了tamplate经过parse函数解析,经过词法分析语法分析生成了AST对象,那么我们这一章就来讲讲在解析编译过程中Vue机制做了哪些优化吧,我们知道Vue就是通过optimize函数进行静态打点操作,以便于后面进行patch dom我们会跳过此节点,不做比较,节省性能。我们首先进入optimizer.js里面

    export function optimize (root: ?ASTElement, options: CompilerOptions) {
      if (!root) return
      // staticKeys 这是被认为是静态节点的标记
      isStaticKey = genStaticKeysCached(options.staticKeys || '')
      isPlatformReservedTag = options.isReservedTag || no
      // 标记 AST 所有静态节点
      markStatic(root)
      // 第二步 标记 AST 所有父节点(即子树根节点)
      markStaticRoots(root, false)
    }
    

    我们直接看到optimize函数里面两个关键函数markStatic(),markStaticRoots(),首先我们来看一下markStatic()函数内部的运行机制:

    function markStatic (node: ASTNode) {
      node.static = isStatic(node)
      if (node.type === 1) {
        // do not make component slot content static. this avoids
        // 1. components not able to mutate slot nodes
        // 2. static slot content fails for hot-reloading
        if (
          !isPlatformReservedTag(node.tag) &&
          node.tag !== 'slot' &&
          node.attrsMap['inline-template'] == null
        ) {
          return
        }
        for (let i = 0, l = node.children.length; i < l; i++) {
          const child = node.children[i]
          markStatic(child)
          if (!child.static) {
            node.static = false
          }
        }
        if (node.ifConditions) {
          for (let i = 1, l = node.ifConditions.length; i < l; i++) {
            const block = node.ifConditions[i].block
            markStatic(block)
            if (!block.static) {
              node.static = false
            }
          }
        }
      }
    }
    

    node.static被赋值isStatic函数的返回值,那么我们来看看isStatic

    function isStatic (node: ASTNode): boolean {
      if (node.type === 2) { // expression(插值表达式)
        return false
      }
      if (node.type === 3) { // text(文本)
        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)
      ))
    }
    

    可以看出这个函数的作用就是标记所有静态节点,分析上面ASTNodetype类型有三种:1为元素节点2为插值表达式3为普通文本节点,当type1或者2的时候,我们不采取措施。markStatic函数就是递归静态节点的子节点是否有被isStatic标记过得静态标记staticmarkStaticRoots函数则是标记ASTElemet树形结构:

    function markStaticRoots (node: ASTNode, isInFor: boolean) {
      if (node.type === 1) {
        if (node.static || node.once) {
          node.staticInFor = isInFor
        }
        // For a node to qualify as a static root, it should have children that
        // are not just static text. Otherwise the cost of hoisting out will
        // outweigh the benefits and it's better off to just always render it fresh.
        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)
          }
        }
      }
    }
    

    这一段注释就非常有意思了:

    // For a node to qualify as a static root, it should have children that
    // are not just static text. Otherwise the cost of hoisting out will
    // outweigh the benefits and it's better off to just always render it fresh.
    

    我们翻译过来就是:一个节点想要有变成静态根的资格,那么它的子节点就不应该仅仅是一个普通静态文本,否则我们把它标记起来(也就是提取出来)的成本要比直接渲染大,性能也不好 这是啥意思呢?说白了就是我们一个根节点里面,假如只有一个普通文本的时候,那么我们直接渲染标记来的更快更高更远 纵观optimize函数,就是两轮遍历:

    • 遍历第一轮,标记static属性:判断node是否为static,标记nodechildren是否为static,若不存在static子节点,父节点更改为static = false
    • 遍历第二轮,标记staticRoot,标记static的节点为staticRoot,标记节点childrenstaticRoot,为了避免过度优化,仅有静态文本的为子节点的节点不被标记为staticRoot,

    那么到这里解析编译第二步optimize已经搞完了,我们应该getVue这一步的核心就是给一些静态节点打标,对后续操作提升一些优化。当你知道后面的diff算法是怎么样diff的,那就会感叹这一步的必要性。下一章我们将继续讲解编译完成AST转为render Function Code的故事-Vue源码解析系列(八) -- 虚拟dom是怎么样生成的


    起源地下载网 » Vue源码解析系列(七) -- 模板tamplate在解析的时候做了哪些优化

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元