Sizzleエンジン--原理と実践(一)

7504 ワード

SizzleはjQueryの御用セレクタエンジンであり、jQueryの著者John Resigが書いたDOMセレクタエンジンであり、速度は業界1位と呼ばれていることはよく知られています.また、Sizzleは独立した一部であり、ライブラリに依存せず、jQueryを使用したくない場合はSizzleのみを使用できます.だから単独で特別扱いします.Prototype 1.7では、セレクタもSizzleを採用していますが、バージョンが少し古いので、Sizzleサイトに行って新しいものを作りました.そこで、以下の分析では最新版のSizzleを使用します.js
あらかじめ説明する
解析初期に各ブラウザの結果が一致することを保証するため、オリジナルgetElementsByClassおよびquerySelectorAllの影響を考慮せずにXMLタイプを無視するため、処理を行う:ソースコード1292行、
(function(){
...
})()

変更後:
(function(){
return false;
...
})()

ソース1140行
if ( document.querySelectorAll ) {
...
}

変更後:
if ( document.querySelectorAll && false) {
...
}

他のブラウザ互換処理部分については、初歩的な分析で併せて説明します.
予備知識
CSSセレクタ , jQueryセレクタ .jQueryセレクタの形式はCSSから来ているが、CSSに加えて多くの新しい選択式が追加されているため、すべてjQueryセレクタに基づいている.
例:
選択式の場合:
div#outer > ul , div p:nth(1),form input[type="text"]

ブロックについての議論
この中には3つの並列選択子が含まれていますが、どうすればいいですか?解決策:1、split(',')で処理できますが、これは単純に分割されただけで、より多くの情報を得ることはできません.2、だから私達は正則を採用してブロックを分けて、欠点は可読性と効率の問題で、利点はいくつか必要な情報を抽出することができて、前処理を行います.
だからjqueryは正則を取っていますが、完全にブロック化するのではなく、一部の取りです.上の例では、ブロックの分割方法を見てみましょう.
div#outer>ul,div p:nth(1),form input[type="text"]先にdiv#outer>ulを分離し,処理が完了してからdiv p:nth(1),処理が完了してからform input[type="text"]を分離し,最後に3つの部分を統合した結果
選択順序についての議論
ここではjQueryセレクタの役割を覚えておく必要があります
典型的な例:
body div p:first-child
body div p:first

この2つの意味は全く違います.カッコで書けば、次のように変更できます.
body div p:first-child --> body div (p:first-child)
body div p:first --> (body div p):first

first-childはpを限定するために用いられ、pの属性とすることができ、body div p:firstはbody div p結果セットを限定するために用いられ、body div p結果セットの1つの方法とすることができる.body div p:first == (body div p).eq(0)
同様にjQueryがカスタマイズしたいくつかの位置クエリー式もあるので、ケース1、body div p:first
左から右へのクエリー.まずbodyを探し当てて、集合Aを獲得して、それから集合Aの中でdivを探して集合Bを獲得して、集合Bの中でpを探して集合Cを獲得して、最後に集合Cの第1の要素を取って、最終的な結果XXを得ます
ケース2、body div p:first-child
右から左へのクエリーでは、まずp:first-childを見つけて集合A 1を取得し、その後、祖先要素の中にdivがあるかどうかを判断して集合B 1を取得し、その後、祖先要素の中にbodyがあるかどうかを判断して集合C 1を取得し、最終結果C 1を得る
上記の2つのプロセスと比較すると、プロセス1に比べて、プロセス2はフィルタリングのプロセスのように見えます.そのため、Sizzleの最大のハイライトは右から左へフィルタリングすることです.
また、クエリーの効率化のためには、検索範囲の縮小と遍歴回数の削減が最も重要です.1つの典型的な例は、div pの場合1、まずpを見つけて集合Aを得て、それから祖先元素の中にdivが入っているかどうかを判断して集合Bを得て、最終結果Bdiv#a p#aは一般的に1つしかないので、状況1の中でpの範囲が大きすぎるので、最初の選択式にidが含まれている場合、Sizzleはいつも最初のものを探して、したがって、検索範囲を縮小する場合2、div#aを先に見つけ、単一の要素A 1を得た後、A 1の環境でpを検索し、最終結果B 1を得る
そのため、最終的な過程は
第1、分割式第2、検索要素第3、フィルタ要素(フィルタは2種類に分けられ、1、要素自身の属性によってフィルタされる2、要素間の関係によってフィルタされる.)
したがって、Sizzleの大まかなコード構造:Sizzleエンジンの基本構造の主な流れ:windowを得ることができる.Sizzle = function(){};検索要素:Sizzle.find = function(){};フィルタエレメント:Sizzle.filter = function(){};
使用するいくつかの検索方法とフィルタ条件を定義します:Sizzle.selectors = {};Sizzle.selectorsはよく使われるので、短い名前をExprと言います.
Sizzleのコードフレームワークは次のようになります.
window.Sizzle = function(){
//
};
Sizzle.find = function(){
//
};
Sizzle.filter = function(){
//
};
Sizzle.selectors = {
//
};
var Expr = Sizzle.selectors;//

残りの問題は、必要な要素の集合をどのように取得するかです.
 
要素の検索に関する初歩的な議論
まず、どのように要素を探すかを見てみましょう.ブラウザは3つの要素を検索する方法しかありません(最初は、getElementsByClassNameが最初にすべてのブラウザがgetElementsByClassNameをサポートしていないと仮定しましたが、ほとんどがサポートされています):getElementById、getElementsByName、getElementsByTagNameです.
問題1:選択式に遭遇したとき、この選択式がどのようにタイプされているかをどのように判断しますか.解決策:この式のタイプを順次検出し、一致するタイプを取得します.一致するタイプが取得されると、一致は続行されません.どのタイプを先にマッチングするかというと,検索原則は検索範囲をできるだけ縮小することである(特異性が高いほど検索範囲が小さくなる).一般に、ID数はNAME数よりも小さく、NAME数はTAG数よりも小さい.そこで判断順が['ID','NAME','TAG']の例説明:1,input[name="test"]であり,先に[name="test"]を検索するが,この場合はinputを検索し続けることもできるが,その必要はない.inputをクエリーしてから交差を取りに行くとプログラムの構造が破壊されるからである.Sizzleの処理は,[name="test"]を検索して集合Aを取得し,その後Aでinputをフィルタリングし,inputをフィルタ条件としてフィルタ部に捨てて処理する.
2、input#demo[name="test"]IDの優先度がNAMEよりも高いため、まず#demoを探して集合Aを取得し、その後Aでinput[name="test"]をフィルタリングし、input[name="test"]はフィルタ条件としてフィルタ部分に捨てて処理される.
フィルタリング要素についての初歩的な議論
フィルタリングは1つの条件1つの条件で行われ、1つの集合Aおよびフィルタ式
expr='[class="test"][rel=1]:first-child'

Aで[class="test"]をフィルタリングして集合Bを得る.このときフィルタ式expr='[rel=1]:first-child'がBでフィルタリング[rel=1]して集合Cを得る.このときフィルタ式expr=':first-child'がCでフィルタリング:first-childが集合Dを得る.このときフィルタ式expr=',フィルタリング完了
【説明、上記の順序は真の順序を表すものではなく、「フィルタリングは1つの条件で1つの条件で行う」という作業を説明するためのものである】フィルタリングは、第1、プリフィルタExpr.prefalterは、互換性の問題およびフォーマット変換を処理し、次のステップの第1、最終フィルタExprへの移行を決定する.filter、このステップの形式は同じで、最終的にはブール値が返されます.
フィルタ方法:
第1ラウンドのフィルタ集合を仮定すると、A=[##1','#2','#3','#4','#5','#6']フィルタ条件がisMatchで条件を満たす集合がC=[##1','#2','#3']である
第一、
var B = [];
for( i = 0; (item = A[i]) != null; i++ ){
A[i] = isMatch(item);
}
for( i = 0; i < A.length; i++ ){
if(A[i]){
B.push(A[i]);
}
}

1、['#1','#2','#3','#4','#5','#6']2、['#1','#2','#3',false,false,false]3、['#1','#2','#3']
第二に、
var B = [];
for( i = 0; (item = A[i]) != null; i++ ){
if(isMatch(item)){
B.push(A[i]);
}
}

次に、メイン・プロセスと必須正則分析:『Sizzleエンジン--原理と実践(二)
 
転載は小西山子から【http://www.cnblogs.com/xesam/】本文住所:http://www.cnblogs.com/xesam/archive/2012/02/15/2352466.html