Sizzle的編譯過程是調(diào)用的Sizzle.compile方法,內(nèi)部執(zhí)行了:
matcherFromTokens matcherFromGroupMatchers
把分析關(guān)系表,生成用于匹配單個選擇器群組的函數(shù)。
matcherFromTokens,它充當(dāng)了selector“分詞”與Expr中定義的匹配方法的串聯(lián)與紐帶的作用,可以說選擇符的各種排列組合都是能適應(yīng)的了。Sizzle巧妙的就是它沒有直接將拿到的“分詞”結(jié)果與Expr中的方法逐個匹配逐個執(zhí)行,而是先根據(jù)規(guī)則組合出一個大的匹配方法,最后一步執(zhí)行。
重點(diǎn)就是:
cached = matcherFromTokens(group[i]);
cached的結(jié)果就是matcherFromTokens返回的matchers編譯函數(shù)了。
matcherFromTokens的分解是有規(guī)律的:
語義節(jié)點(diǎn)+關(guān)系選擇器的組合
div > p + div.aaron input[type="checkbox"]
Expr.relative 匹配關(guān)系選擇器類型,當(dāng)遇到關(guān)系選擇器時elementMatcher函數(shù)將matchers數(shù)組中的函數(shù)生成一個函數(shù)。
在遞歸分解tokens中的詞法元素時,提出第一個typ匹配到對應(yīng)的處理方法:
matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
"TAG": function(nodeNameSelector) { var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase(); return nodeNameSelecto r === "*" ? function() { return true; } : function(elem) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; },
matcher其實(shí)最終結(jié)果返回的就是bool值,但是這里返回只是一個閉包函數(shù),不會馬上執(zhí)行,這個過程換句話就是編譯成一個匿名函數(shù)。
繼續(xù)往下分解:
如果遇到關(guān)系選擇符就會合并分組了
matchers = [addCombinator(elementMatcher(matchers), matcher)];
通過elementMatcher生成一個終極匹配器:
function elementMatcher(matchers) { //生成一個終極匹配器 return matchers.length > 1 ? //如果是多個匹配器的情況,那么就需要elem符合全部匹配器規(guī)則 function(elem, context, xml) { var i = matchers.length; //從右到左開始匹配 while (i--) { //如果有一個沒匹配中,那就說明該節(jié)點(diǎn)elem不符合規(guī)則 if (!matchers[i](elem, context, xml)) { return false; } } return true; } : //單個匹配器的話就返回自己即可 matchers[0]; }
看代碼大概就知道,就是分解這個子匹配器了,返回又一個curry函數(shù),給addCombinator方法:
matcher為當(dāng)前詞素前的“終極匹配器”,combinator為位置詞素,根據(jù)關(guān)系選擇器檢查,如果是這類沒有位置詞素的選擇器:“#id.aaron[name="checkbox"]”,從右到左依次看看當(dāng)前節(jié)點(diǎn)elem是否匹配規(guī)則即可。
但是由于有了位置詞素,那么判斷的時候就不是簡單判斷當(dāng)前節(jié)點(diǎn)了,可能需要判斷elem的兄弟或者父親節(jié)點(diǎn)是否依次符合規(guī)則。
這是一個遞歸深搜的過程。
所以matchers又經(jīng)過一層包裝了,然后用同樣的方式遞歸下去,直接到tokens分解完畢。返回的結(jié)果一個根據(jù)關(guān)系選擇器分組后在組合的嵌套很深的閉包函數(shù)了,整個函數(shù)編譯的過程,就結(jié)束了,其實(shí)整個流程總結(jié)就干了那么幾件事:
1、在Expr.filter找出每一個選擇器類型對應(yīng)的處理方法
2、從右邊往左,向父級匹配的時候。注意詞素關(guān)系,引入relative記錄這個映射的關(guān)系
3、把對應(yīng)的處理函數(shù)壓入matchers數(shù)組
整個編譯過程就完成了,其實(shí)粗看就是把函數(shù)一層一層包裝下去,之后通過匹配器傳入對應(yīng)的種子合集seed一層一層的解開。
請驗(yàn)證,完成請求
由于請求次數(shù)過多,請先驗(yàn)證,完成再次請求
打開微信掃碼自動綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報