天天看點

sizzle分析記錄:分解流程

<a></a>

js

解析的流程:

編譯器:分5個步驟

涉及: TAG元素 關系選擇器 屬性選擇器

1:通過tokenize詞法分析器分組

sizzle分析記錄:分解流程

2:周遊tokens,從右邊往左邊開始篩選,最快定位到目标元素合集

操作如下

那麼第一篩選找到的定位元素,就形成了一個 seed種子合集,那麼餘下的所有的操作都是圍繞這個種子合集處理

因為節點總是存在各種關系的,是以不管是通過這個最靠近的目标的元素,往上還是往下 都是可以處理的

3:重組選擇器,開始執行繼續分解"form div &gt; [name=aaron]"

因為種子合已經抽出了,是以選擇器就需要重新排列

踢掉了P元素,已經被抽離了

4 : 生成編譯處理器

這裡為什麼要這麼複雜,因為生成了編譯閉包可以緩存起來,通過這種機制,增加了重複選擇器的效率

在matcherFromTokens方法中通過分解tokens生成對應的處理器

例如:form div [name=aaron]

在分解過程中分2大塊

A:關系選擇器的處理  &gt; + ~ 空

B: ATTR CHILD CLASS ID PSEUDO TAG的處理

用matchers保留組合關系

1:分解第一個TAG:form 儲存處理器到matchers.push( Expr.filter[“TAG”]) ;

2:分解第二個“空”的關系選擇器,此時

 A:用elementMatcher把之前的matchers壓入到這個比對裡面,生成一個周遊方法的處理
B:用addCombinator再次包裝,生成一個位置關系的查找關系

是以此時的matchers的關系是一個層級的包含結構,然後依次這樣遞歸

sizzle分析記錄:分解流程

這個地方相當繞!!!!

生成的最後

cached = matcherFromTokens( match[i] );

變成了一個超大的嵌套閉包

5: 通過matcherFromGroupMatchers這個函數來生成最終的比對器

通過matcherFromGroupMatchers的處理最直接的就是能看出,elementMatchers, setMatchers 2個結果不需要再傳回出去,直接形成curry的方法,在内部就合并參數

外面就直接調用了,這樣

compileFunc 一直是持有elementMatchers, setMatchers 的引用的,這個設計的手法還是值得借鑒的

執行期:

至此之前的5個步驟都是編譯成函數處理器的過程,然後就是開始執行了

粗的原理就是把直接分解出來的seed種子合集丢到這個處理器中,然後處理器就會根據各種關系進行分解比對

進而得到結果集

superMatcher:

抽出第一個seed元素,p

然後把p丢到atrr是過濾篩選器中去比對下,看看是否能找到對應的這個屬性

當然還是繼續從右往左邊比對過濾了

一次是【name=aaron】 =&gt; div =&gt; from

matchers[i] =&gt; Expr.filter.ATTR =&gt;

p.getAttribute(‘name=aaron’) =&gt; 得到結果

如果比對失敗,自然就退出了  return false ,就不需要在往前找了 ,然後再次遞歸seed

如果成功,就需要再深入的比對了

因為是從右到左逐個比對,是以往前走就會遇到關系選擇器的問題,

那麼jQuery把四種關系 &gt; + ~ 空的處理給抽出一個具體的方法就是addCombinator

sizzle對選擇器的大概是思路:

分解所有的選擇器為最小單元,從右往左邊開始挑出一個浏覽器的API能快速定位的元素TAG,ID,CLASS節點,這樣就能确定最終的元素跟這個元素是有關系的

然後把剩餘的選擇器單元開始生成一個比對器,主要是用來做篩選,最後根據關系分組

如果就依次比對往上查找,通過關系處理器定位上一個節點的元素,通過普通比對器去确定是否為可選的内容

本文轉自艾倫 Aaron部落格園部落格,原文連結:http://www.cnblogs.com/aaronjs/p/3857899.html,如需轉載請自行聯系原作者

繼續閱讀