JQuery Sizzle Engine Source code Analysis

Source: Internet
Author: User

In a recent reading of the jquery course that Allen wrote on the web, he felt that few people in the country who had a thorough analysis of the jquery code were able to compare Allen. Did you brag? Am I a big talker?

What is the sizzle engine?

We often use jquery's selector to query for elements, and the selectors for queries are simple and complex:
Simple points: "div", ". Navi", "Div.navi".

Complex points: "Div input[type= ' checkbox '", "Div.navi +. Section P".

Query implementation also takes precedence over DOM standard query functions, such as:

document.getElementById ()

document.getElementsByTagName ()

Document.getelementsbyclassname ()

Document.getelementsbyname ()

The advanced browser also implements:

Queryselector ()

Queryselectorall ()

The above functions are not supported by all browsers due to compatibility issues caused by browser version differences. But jquery had to solve these problems, so we introduced the sizzle engine.
jquery takes precedence over the advanced query functions that are available in the browser when filtering elements because of the high efficiency of the query. The second option is to use the sizzle engine to filter the elements.

The purpose of the sizzle engine is to filter out the collection of elements based on the incoming selector selector. The execution process undergoes lexical analysis and compilation process. A selector string is decomposed into structured data for use in the compilation process through lexical analysis. The compilation process takes full advantage of the JavaScript closure function, generating a function chain that executes the function chain when the final match is made.

For example, the value of a selector selector "Aaron input[name=ttt]", through lexical analysis, to get a structured array:

[    {        matches: ["div"],        "TAG",        "Aaron"    },    {        "" ,        " "     },    {        matches: ["name", "=", "TTT"],        "ATTR",        "[name=ttt]"    }] 

The input in selector as a seed collection seed. This means that sizzle queries all input elements based on input, and the results are stored in the seed collection, and the compilation process is query filtering in the seed collection.
The above is very rough, not easy to understand, then we will take the code to introduce.

By Code Analysis principle

Disclaimer: The following code comes from Aaron's jquery tutorial on the online course

Compile

/** * Compile process*/functioncompile () {varSeed = Document.queryselectorall ("Input"), selector= "Aaron [NAME=TTT]", Elementmatchers=[], Match=[{matches: ["Div"], type:"TAG", Value:"Aaron"}, {type:" ", Value:" "}, {matches: ["Name", "=", "TTT"], type:"ATTR", Value:"[NAME=TTT]"            }        ];    Elementmatchers.push (Matcherfromtokens (match)); //super-matching device    varcached =matcherfromgroupmatchers (elementmatchers); varResults =cached (seed); results[0].checked = ' checked ';}

The compile function of jquery contains all the execution, because the focus of this article is the compilation process, so the lexical analysis process is not included, here directly write the match result, the actual jquery will call the Tokenize () function to get the phrase.
Two functions are called in the function: Matcherfromtokens () and Matcherfromgroupmatchers ().
Matcherfromtokens (): returns a function with the following function:

The return function is formatted as functions (Elem, Context, XML), and this function returns a bool value indicating whether the Elem match is valid.

matcherfromgroupmatchers (): The function code is simple, traversing the seed collection, and each element calls the Elementmatcher function. Finally returns a collection of elements that match successfully.
Since the Matcherfromgroupmatchers () function is relatively simple, it is introduced first.

matcherfromgroupmatchers

functionmatcherfromgroupmatchers (elmentmatchers) {return function(seed) {varResults = []; varMatcher, Elem;  for(vari = 0; i < seed.length; i++){            varElem =Seed[i]; Matcher= Elmentmatchers[0]; if(Matcher (elem)) {Results.push (elem); }        }        returnresults; }}

Traversing the seed element, each element calls the Matcher function, and returns true to the results array.

  Matcherfromtokens
functionMatcherfromtokens (tokens) {varLen =tokens.length, Matcher, Matchers= [];  for(vari = 0; i < Len; i++){        if(Tokens[i].type = = = "") {matchers=[Addcombinator (Elementmatcher (matchers))]; }Else{Matcher= Filter[tokens[i].type].apply (NULL, tokens[i].matches);        Matchers.push (Matcher); }    }    returnElementmatcher (matchers);}

The core of the whole compilation is also in the Matcherfromtokens function, traversing the word tokens array, Word segmentation divided into two categories, relational and non-relational type. Relationship types include: "," > "," + "," ~ ". The rest are non-relational participle.

Each non-relational participle will correspond to a matcher:

The first participle type is tag, and the Matcher is found in the filter. The second participle is a relationship participle, and the matcher before the addcombinator merge is called. The third participle type is attr, and the Matcher is found in the filter. The value of the final matchers is:

In return, the Elementmatcher () function is called, and the returned result is a function. The function structure returned is seen when the compile function is described above.
The Matcherfromtokens function body is useful in the Addcombinator () and Elementmatcher () functions as well as the filter object. First Look at filter:

varFilter ={ATTR:function(name, Operator,check) {return function(elem) {varattr =Elem.getattribute (name); if(operator = = "="){                if(attr = = =check) {                    return true; }            }            return false; }}, TAG:function(nodenameselector) {return function(elem) {returnElem.nodename && elem.nodeName.toLowerCase () = = =Nodenameselector; }    }}

At a glance, it is known that the attr and tag in the filter correspond to the type types in the match sub-phrase, so the filter corresponds to the Matcher function of the non-relational word breaker.

Addcombinator

 function   Addcombinator (matcher) { return  function   (Elem, context, XML) { while  (elem = elem[" ParentNode "") { if  (Elem.nodetype = = 1 )  //  Find the first intimate node and immediately use the ultimate match to determine if the node conforms to the previous rule  return   Matcher (elem); }    }}

Addcombinator corresponds to the relationship type participle matcher. This example only lists the combination of ancestor and descendant relationship "", the result of which is a function signed as functions (Elem, CONTENXT, XML), elem["parentnode" in the function to find the parent node of the document element type. Call Matcher again to verify that the parent node matches.
So the relational Matcher function executes the process of finding the matching element through the relationship type and then calling Matcher to verify the matching result.

Elementmatcher

functionElementmatcher (matchers) {returnMatchers.length > 1?function(elem, context, XML) {vari =matchers.length;  while(i--){                if(!Matchers[i] (elem, context, XML)) {                    return false; }            }            return true; }: matchers[0];}

The Elementmatcher () function is the guy doing the work, traversing the Matchers function array, executing each matcher function, and once matchers[i] returns false the entire match fails. One thing to note here is i--, why is it a reverse-order traversal? Because the principle of jquery sizzle matching is to go from right to left. Since the previous match array is saved from left to right according to the selector, this is done first.

All of the above code simply simulates the execution of the jquery sizzle engine, the real source code is complex, and it is estimated that only the great God can comprehend it thoroughly. Big God, Allen has to be counted one.

When it comes to closures, if you can analyze the jquery sizzle code thoroughly, it's easy to understand closures. The function return values described in this article are functions, and the variables required for each return function are stored by the closure and then read when the function is actually executed.

If this article is helpful, please click on the attention in the lower right corner of the page. If you feel bad, also welcome to shoot bricks. Your evaluation is the power of the blogger! Next content, please look forward to!

JQuery Sizzle Engine Source code Analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.