This is the 11th day of my participation in Gwen Challenge.

preface

Previously we looked at parsers in template compilation, this time we’ll look at optimizers.

The optimizer

The role of the parser is to parse the HTML template into an AST, and the role of the optimizer is to find and tag static subtrees in the AST.

What is a static subtree?

Static subtrees are nodes that never change in the AST. For example, a plain text node is a static subtree, whereas a text node with variables is not a static subtree because it changes with variables.

benefits

Marking static subtrees has two benefits:

  • There is no need to create a new node for the static subtree each time you re-render
  • inVirtual DOMThe patching process can be skipped

Why is there no need to create new nodes for static subtrees when rerendering?

We talked about cloning nodes earlier. During VNode generation, if a node is identified as a static subtree, no new subtree is generated during re-rendering except for the first rendering. Instead, the existing static subtree is cloned.

Why can I skip the patch phase?

If both nodes are static subtrees, there is no need to compare and update the DOM. Because static subtrees are immutable, no comparison is required to know that they cannot change. In addition, skipping the various comparisons that follow can save JavaScript computation costs.

Internal implementation

The internal implementation of the optimizer consists of two main steps:

  • Find all of them in the ASTStatic nodeAnd mark it
  • Find all of them in the ASTStatic root nodeAnd mark it

Nodes like the following are static nodes:

<p>I'm a static node<p>
Copy the code

Static is true for the AST, and staticRoot is true for the static root.

Find all static nodes and mark them

If the type of the node is equal to 1, the node is an element node. Then loop through the child node of the node and call markStatic to process the child node using the same processing logic:

function markStatic(node){
    node.static = isStatic(node);
    if (node.type === 1) {
        for (let i = 0, l = node.children.length; i<l; i++){constchild = node.children[i]; markStatic(child); }}}Copy the code

What kind of nodes are static?

When a template is parsed into an AST by the parser, different type values are set for different element types

type instructions
1 Element nodes
2 Dynamic text node with variable
3 A plain text node with no variables

Obviously, a text node with no variables is a static node, and then a static node without v-if, V-else, V-for, or v-bind.

Custom or built-in components are also not static nodes.

Since recursion is marked from top to bottom, a contradiction occurs if the parent node is marked as static and the child node is marked as dynamic. Because it should not be the only static node in a static subtree, all the children of a static subtree should be static nodes. Therefore, we need to recalibrate the marking of the current node after the child node is marked.

function markStatic(node){
    node.static = isStatic(node);
    if (node.type === 1) {
        for (let i = 0, l = node.children.length; i<l; i++){const child = node.children[i];
            markStatic(child);
            / / new
            if(! child.static){ node.static =false}}}}Copy the code

We need to determine if it is a static node, and if it is not, its parent cannot be static either.

Find all static root nodes and mark them

The process of finding the static root node is similar to the process of finding the static node in a recursive manner. If a node is judged to be static root, the search for its children is not continued.

Graph root ((root)) - found - > a ((static)) root - didn't find - > b (a) (b) b - found - > c ((static)) a - > d ((static)) a - > e (static) (c) - > f (static) (c) --> g(static)

In one case, it won’t be marked as a static root even if it really is, because the optimization costs outweigh the benefits. This is the case where an element node has only one text node.

Such as:

<p>I'm a static node<p>
Copy the code

The p element has only one text child node, which is not marked even if it is the static root node.

function markStaticRoots(node){
    if (node.type === 1) {
        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]) } } } }Copy the code

conclusion

In this article, we’ve learned what the optimizer does and how it works, and we’ll move on to the third part of template compilation, the code generator.