最近在啃jQuery1.11源碼,上來就遇到Sizzle這個jQuery的大核心,雖然已經清楚了Sizzle的用途,先繞過去也沒事,但明知山有虎偏向虎山行纔是咱們要作的。html
本文面向的閱讀對象:正在學習Sizzle源碼或有必定前端基礎的同窗們,能夠一邊看源碼一邊看這些文章進行驗證,因此雖然我會分析源碼中的正則表達式,有大量的註釋,但不會講正則表達式的基本用法!(我會給出一些連接,但不必定全面,請鍛鍊自主搜索的能力;爲了不歧義,本文的一些詞會採用源碼中的英文或js中的屬性名)前端
Sizzle部分的代碼已經啃完,本系列還有後續,這幾天將會一一放出。本文主要分爲兩個部分:什麼是Sizzle、Sizzle的原理以及Sizzle結構概覽node
什麼是Sizzle?jquery
簡單地來講,Sizzle是一個可讓你用CSS 選擇器(selector)形式去獲取DOM元素的引擎。正則表達式
當咱們想了解一個函數的用途和源碼,必須先看它的要求和效果,就是輸入和輸出。api
例如:你提供一個CSS selector 'html > body',Sizzle會返回給你一個數組,數組中只有一個元素body元素。數組
還有更復雜的CSS selector,好比 ‘body > div#main div.content input[type="text"]:nth(2)’,更多selector的用法請看瀏覽器
Sizzle的原理函數
咱們先想一想,若是讓咱們本身寫一個Sizzle,先不考慮其中遇到的設計和細節問題,你會怎麼作?
一個很天然的想法是,從父元素順藤摸瓜往下一層層找下去。好比‘html > body’,我先找到nodeName爲html的元素,再查看html的子元素裏有沒有一個nodeName爲body的元素便可。
那麼會面對幾個問題:
你怎麼知道在哪兒找html元素?因而咱們須要一個查找上下文(context),默認爲文檔節點(document)
你怎麼知道要找的是html元素而非h元素或者ht元素?因此咱們須要一個詞法分析器(tokenize),把selector切成三個詞元(token)(一個數組(tokens)),[‘html’,'>','body']。(關於詞法分析器,請學習編譯原理相關知識)
難道處理‘html’和處理‘>’的方式是同樣的?你怎麼知道它要查找子元素?咱們知道它們是不一樣的類型的詞元(token),因此要記錄詞元的類型,上面的數組變爲[{value:'html',type:'TAG'},{value:'>',type:'>'},{value:'body',type:'TAG'}],再交給對應的處理函數處理
難道每次咱們都來上面這麼一套麼?咱們常常用的不就是$('#id')或者$('.className')這樣簡單的用法麼?因此咱們能夠把這種高頻率的特殊狀況拿出來先處理,處理不掉再用統一的方法處理。
上面這一套,從左往右匹配,從邏輯上來看是沒什麼問題的。那麼思考下面這種狀況:
‘由於DOM是一種樹形結構,因此越往下層,子節點是越多的,那麼會有這樣一種狀況,body元素下有10000個div子元素,其中在5000的位置處有一個div的id爲suprise。’這時給你一個內容爲body > div#suprise的selector,你寫的引擎會怎麼處理?
繼續用上面的方法,先找出body元素,而後一個個遍歷body的子元素?
能夠預見的是性能上的悲劇。。。
因此咱們的Sizzle採用的是從右向左的匹配方式:
先調用getElementById('suprise')來得到該DOM元素(find過程)(由於瀏覽器低層目測會創建id的索引,因此得到很是快,即便須要遍歷DOM樹,也比咱們本身遍歷DOM樹快),
再根據'>'判斷其父元素是不是body元素(filter過程)便可。
OK,到這裏爲止性能方面有了必定的改進,再考慮一種狀況:
'當咱們須要查找的層次很深時,好比selector爲body > div#main div.content input[type="text"]時,咱們須要先找到待選(seed)的input,再依次過濾[type="text"]、div.content 、div#main 、body>,大家會怎麼作?'
判斷不一樣的token類型,再經過查找找到對應的過濾函數,並調用對應的過濾函數(filter),這是一個正常的想法。
那麼我須要再用該selector來查找一次呢?(這是使用jQuery很是常見的場景)把上面的過濾過程再重複一遍?
因而另外一種提高性能的方式出現了——緩存,把上面的多個過濾函數編譯成一個匹配函數(matcher),而後以key-value的形式存在緩存裏面,當咱們再次查找一樣的selector時,只須要把編譯好的匹配函數(matcher)給取出來過濾用就能夠了。
Sizzle的所有原理大體如上,至於特性檢測、沙盒、bugfix這些細節,後面再說
Sizzle的結構概覽
Sizzle的結構不用記,大體看看就好,後面會一一說到的,放一張圖,來源:http://www.cnblogs.com/mufc-go/p/3299261.html
本文完。
剩下的下午健完身回來再發。
感謝@司徒正美(1.3版本源碼分析),@nuysoft(1.7版本源碼分析),@Aaron(2.03版本源碼分析)給個人參考。
若是你喜歡這篇文章,請給我一個推薦,若是以爲有問題,請在評論裏抽打我!