优化一些不依赖响应式数据的 AST,具体是做了标记静态节点和标记静态根,如果是静态节点,DOM 永远不需要改变。这样标记的目的是对模版更新做性能优化 代码片段 入口 标记静态节点,静态节点的特点 是纯文本 普通元素有 v-pre 指令 没有使用 v-if,v-for,非 v-once 外的其他指令,非内置组件,是平台保留标签,没带 v-for 的 template 标签的直接节点,所有属性都是静态…

优化一些不依赖响应式数据的 AST,具体是做了标记静态节点和标记静态根,如果是静态节点,DOM 永远不需要改变。这样标记的目的是对模版更新做性能优化

代码片段

入口

// src/compiler/optimizer.js
export function optimize(root: ?ASTElement, options: CompilerOptions) {
  if (!root) return;
  isStaticKey = genStaticKeysCached(options.staticKeys || '');
  isPlatformReservedTag = options.isReservedTag || no;
  // 标记静态节点
  markStatic(root);
  // 标记静态根
  markStaticRoots(root, false);
}

function genStaticKeys(keys: string): Function {
  return makeMap('type,tag,attrsList,attrsMap,plain,parent,children,attrs' + (keys ? ',' + keys : ''));
}

标记静态节点,静态节点的特点

  1. 是纯文本
  2. 普通元素有 v-pre 指令
  3. 没有使用 v-if,v-for,非 v-once 外的其他指令,非内置组件,是平台保留标签,没带 v-for 的 template 标签的直接节点,所有属性都是静态属性 这些都满足才是一个静态节点
  4. 如果 AST 本身是静态节点,但是有 children,并且 children 是非静态的,那么这个 AST 就变成非静态
// src/compiler/optimizer.js
function markStatic(node: ASTNode) {
  // 判断是否是一个静态节点
  node.static = isStatic(node);
  if (node.type === 1) {
    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;
        }
      }
    }
  }
}

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))
  );
}

标记静态根,静态根的特点

  1. 本身是静态节点
  2. 只有一个 children
  3. children 是文本节点
// src/compiler/optimizer.js
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);
      }
    }
  }
}

暂无评论