This is the 26th day of my participation in the First Challenge 2022.
Previously on & Background
My last essay mainly completed the following tasks:
parseHTML
The last callback method ofoptions.end
The discussion;- it
curerntParent
在start
和end
The updating function of the - Review the entire
parse
methodsparseHTML
The synopsis method and its function;
The previous section covered the process of obtaining an AST from an HTML template using the Parse method. The following sections will continue. This short article will focus on static markup optimization after the AST is generated.
Static tag calls in baseCompile
After Parse generates the AST, the optimize method is called for static markup processing.
export const createCompiler = createCompilerCreator(function baseCompile (template: string, options: CompilerOptions) :CompiledResult {
const ast = parse(template.trim(), options)
// Optimize for static marking of each node
if(options.optimize ! = =false) {
optimize(ast, options)
}
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
})
Copy the code
Optimize method
Methods location: SRC/compiler/optimizer. Js – > function to optimize
Method parameters:
root
And the topast
Node object;options
: compiler option object
Methods:
- generate
isStaticKey
The function,isStaticKey
Function is a function that checks whether certain properties are static properties,options.staticKeys
是'staicClass,staticStyle'
This string, this string also comes frombaseOptions
.baseOptions
fromcreateCompiler(baseOptions)
The incoming;- 1.1
isStatic
The method is to receive somekey
Judge thiskey
Whether it istype,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap,staticStyle,staticClass
One of them. The implication is that these are all listedast
Static attributes;
- 1.1
- traverse
root
Node, set for each nodestatic
Property, which identifies whether the current node is static;
Nodes marked as static nodes will not be paid attention to during data update, and these static nodes will also be ignored during patch.
export function optimize (root: ? ASTElement, options: CompilerOptions) {
if(! root)return
isStaticKey = genStaticKeysCached(options.staticKeys || ' ')
// Whether to keep the platform label
isPlatformReservedTag = options.isReservedTag || no
// Walk through the nodes and give each node a static attribute to indicate whether it is static
markStatic(root)
// Mark the static root
markStaticRoots(root, false)}Copy the code
3.1 genStaticKeysCached
Methods location: SRC/compiler/optimizer. Js – > const genStaticKeysCached
Method argument: STR
The caches () method returns a function that takes the result from the cache first.
const genStaticKeysCached = cached(genStaticKeys)
Copy the code
3.1.1 cached
SRC /shared/util.js -> function cached
Method parameter: fn, objective function
The caches () method creates a cache object and returns a new function that takes precedence over the cached result. When the new function is executed for the first time, the return value of the function is placed in the cache
export function cached<F: Function> (fn: F): F { const cache = Object.create(null) return (function cachedFn (str: String) {const hit = cache[STR] // If hit has a value, it hit the cache. Otherwise, fn is called and the result is cached. Fn is below 3.1.2 genStaticKeys return hit | | (cache (STR) = fn (STR))} : any)}Copy the code
3.1.2 genStaticKeys
Methods location: SRC/compiler/optimizer. Js – > genStaticKeys
Method parameters:
keys
By:.
separatedkey
Composed of strings
The keys () method returns a function that verifies whether the key is in the map after calling makeMap.
function genStaticKeys (keys: string) :Function {
return makeMap(
'type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap' +
(keys ? ', ' + keys : ' '))}Copy the code
3.1.2 makeMap
SRC /shared/util.js -> functions makeMap
Method parameters:
str
, separated by,key
Composed of stringsexpectLowerCase
, whether lowercase
The STR () method returns a function to check whether a key is in the map. The STR () method returns a function to check whether a key is in the map.
export function makeMap ( str: string, expectsLowerCase? : boolean ): (key: string) => true | void { const map = Object.create(null) const list: Array<string> = str.split(',') for (let i = 0; i < list.length; i++) { map[list[i]] = true } return expectsLowerCase ? val => map[val.toLowerCase()] : val => map[val] }Copy the code
3.2 markStatic
Methods location: SRC/compiler/optimizer. Js – > functions provides markStatic
Method parameters: node, AST node object
Methods:
-
Set the static property of node to the value returned by the isStatic(node) method.
-
In this process, children of node are traversed, so each child in children is recursively processed. If child is a non-static node, node itself cannot be counted as a static node.
-
In addition, if Node. ifConditions exist, then Node has v-if/ V-else/V-else instructions and recursively processes blocks in each condition statement. If blocks are not static elements, then Node is not static either. The node stack = false
-
The recursion terminates if the node is not a platform reserved tag && not a slot tag && not an inline template; In other words, what can be statically tagged? Is the platform reserved tag or slot tag or inline template
function markStatic (node: ASTNode) {
node.static = isStatic(node)
if (node.type === 1) {
// Do not set the component's slot contents to static nodes to avoid:
// 1. Components cannot change slot nodes
// 2. Static slot content fails when hot reloaded
if(! isPlatformReservedTag(node.tag) && node.tag ! = ='slot' &&
node.attrsMap['inline-template'] = =null
) {
// Recursive terminating condition:
return
}
// Iterate over the child nodes, recursively calling markStatic to mark the child node static properties
for (let i = 0, l = node.children.length; i < l; i++) {
const child = node.children[i]
markStatic(child)
// If the child node is non-static, update the parent node to static
if(! child.static) { node.static =false}}// If node.ifConditons exist, the node has v-if/ V-else -if/ V-else directives
Node.ifcondtions [].block
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
}
}
}
}
}
Copy the code
3.2.1 isStatic
Methods location: SRC/compiler/optimizer. Js – > function isStatic
Method parameters: node, AST node object
Function: Determine whether the node object is static. The criteria are as follows:
node.type === 2
Is the expression, is dynamic; And by the way,node.type
为2
Do you remember where it was created? Yes, it isparse
Method resolutionhtml
Called when the template parses to textoptions.chars
Method,options.chars
Will determine if there is one in the text{{}}
This syntax, if any, is creatednode.type
为2
的ast
Node;node.type === 3
Is text and is static- Comprehensive judgment conditions, meet one of the following conditions:
- 3.1 in
pre
In the tag, that is<pre></pre>
The parcel; - 3.2 The following conditions are true:
- 3.2.1
el.hasBindings
Don’t fortrue
- 3.2.2
el.if
There is no - 3.2.3
node.for
There is no - 3.2.4 not
slot
或compnent
These two built-in tags - 3.2.5 with
v-for
的template
Direct child of - 3.2.6
node
All properties on are static properties
- 3.2.1
- 3.1 in
So when is true?
When prcessAttrs() is called, el.hansbindingds is set to true if the element has an instruction, which is a Vue instruction containing a shorthand such as /@.
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 binding! node.if && ! node.for &&// No v-for, V-if/V-else -if/v-else! isBuiltInTag(node.tag) &&// Not a built-in slot or component tag
isPlatformReservedTag(node.tag) && // Is a platform reserved label, i.e., not a custom component! isDirectChildOfTemplateFor(node) &&// Is not a direct child of template with v-for
Object.keys(node).every(isStaticKey) // Each property on node is a static property))}Copy the code
3.3 markStaticRoots
Methods location: SRC/compiler/optimizer. Js – > markStaticRoots
Method parameters:
node
.ast
The node object
The static root () method further marks the static root node. For a node to become a static root node, it must satisfy:
- The first is the element node, i.e
node.type === 1
; - The element must be static, i.e
node.statick === type
- It has to have child elements, which are
node.children.length
- Elements cannot have only one text node
Why are there so many requirements? 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. Because otherwise, it is much more expensive to raise the static root of these node bits than to render them directly with each update
function markStaticRoots (node: ASTNode, isInFor: boolean) {
if (node.type === 1) {
if (node.static || node.once) {
// The node is static or has a V-once directive marking Node. StaticInFor = true or false
node.staticInFor = isInFor
}
if(node.static && node.children.length && ! ( node.children.length ===1 &&
node.children[0].type === 3
)) {
// The node itself is static and has children, which are not just text nodes
node.staticRoot = true
return
} else {
// Otherwise mark it as a non-static root
node.staticRoot = false
}
// When the current node is not the static root, recursively process the child nodes, trying to mark the static root
if (node.children) {
for (let i = 0, l = node.children.length; i < l; i++) { markStaticRoots(node.children[i], isInFor || !! node.for) } }// If the node has v-for/ V-else -if/ V-else instructions, then try to handle the block node to mark the static root
if (node.ifConditions) {
for (let i = 1, l = node.ifConditions.length; i < l; i++) {
markStaticRoots(node.ifConditions[i].block, isInFor)
}
}
}
}
Copy the code
Four,
This article describes the process of statically marking the AST obtained by Parse. The point of this process is that the AST nodes are marked as static and will not be re-rendered when the data is updated. The core implementation is in the Optimize method:
- call
genStaticKeysCached
To obtainisStaticKeys
Method standby; - call
markStatic
Method recursive processingast
Nodes and their children and conditional render nodes, set for each nodestatic
Property with a value ofisStatic()
Method return value,isStatic
The method is based onast
Determine whether the information on the node object is static; - call
markStaticRoot()
Check whether the node is a static root. The static root node will be ignored during data update and will not bepatch