天天看點

名站技術分析 — facebook奇特的頁面加載技術

 沒事使用代理上了下facebook,注冊進入個人首頁後,習慣性的檢視源代碼,發現了1個很有意思的現象,首頁内容不少,但源代碼中HTML的代碼卻很少,但去多出了很多段的javascript代碼,這些js代碼都是用于動态生成html的,facebook為什麼需要這樣做了?出于職業習慣,研究研究:

一、html代碼。

     先看看首頁檢視的源代碼,因為源代碼比較大,是以把圖檔壓縮了下,可能看不太清楚,隻需要注意圖中紅色是html代碼,其餘黑壓壓一片的就全部是JS代碼:

二、JS代碼

     看到黑壓壓的JS代碼是不是被吓一跳,下面就截取一段JS來分析(其餘段的JS都是類似的),facebook源代碼中充斥了類似于下面的JS代碼:

<code>&lt;script&gt;</code>

<code>big_pipe.onPageletArrive({</code>

<code>    </code><code>"id"</code><code>:</code><code>"pagelet_welcome_box"</code><code>,</code><code>"phase"</code><code>:1,</code><code>"is_last"</code><code>:</code><code>false</code><code>,</code><code>"append"</code><code>:</code><code>false</code><code>,</code><code>"bootloadable"</code><code>:[],</code>

<code>    </code><code>"css"</code><code>:[</code><code>"lDRwi"</code><code>,</code><code>"eon+N"</code><code>],</code>

<code>    </code><code>"js"</code><code>:[</code><code>"F+B8D"</code><code>,</code><code>"IdQlc"</code><code>],</code>

<code>    </code><code>"resource_map"</code><code>:[],</code><code>"requires"</code><code>:[],</code><code>"provides"</code><code>:[],</code>

<code>    </code><code>"onload"</code><code>:[</code><code>"window.__UIControllerRegistry[\"c4c13a3ed2dd1e0e349b72\"] = new UIPagelet(\"c4c13a3ed2dd1e0e349b72\", \"\\\/pagelet\\\/generic.php\\\/WelcomeBoxPagelet\\\/\", {}, {});; ;"</code><code>],</code>

<code>    </code><code>"onafterload"</code><code>:[],</code><code>"onpagecache"</code><code>:[],</code><code>"onafterpagecache"</code><code>:[],</code><code>"refresh_pagelets"</code><code>:[],</code><code>"invalidate_cache"</code><code>:[],</code>

<code>    </code><code>"content"</code><code>:{</code>

<code>        </code><code>"pagelet_welcome_box"</code><code>:</code><code>"&lt;div id=\"c4c13a3ed2dd1e0e349b72\"&gt;&lt;div class=\"UIImageBlock clearfix fbxWelcomeBox\"&gt; ...這裡省略N多HTML"</code>

<code>        </code><code>},</code>

<code>    </code><code>"page_cache"</code><code>:</code><code>true</code>

<code>});</code>

<code>&lt;/script&gt;</code>

讓我們再看看big_pipe.onPageletArrive函數到底做了什麼了?我們隻關注參數中的id,js,css,content4個參數,可以看出js和css都是進行過編碼,下面是解碼後我們關注的代碼:

<code>    </code><code>"id"</code><code>:</code><code>"pagelet_welcome_box"</code><code>,</code>

<code>    </code><code>"css"</code><code>:{</code>

<code>        </code><code>name:</code><code>"css/c5mv8gd5gwoc4kk0.pkg.css"</code>

<code>        </code><code>permanent:</code><code>true</code>

<code>        </code><code>src:</code><code>"http://static.ak.fbcdn.net/rsrc.php/zBP3B/hash/abee68r4.css"</code>

<code>        </code><code>type:</code><code>"css"</code>

<code>    </code><code>},</code>

<code>    </code><code>"js"</code><code>:{</code>

<code>        </code><code>name:</code><code>"js/19khsprwvtvokwow.pkg.js"</code>

<code>        </code><code>permanent:</code><code>false</code>

<code>        </code><code>src:</code><code>"http://static.ak.fbcdn.net/rsrc.php/zAVXU/hash/e8mwcqsi.js"</code>

<code>        </code><code>type:</code><code>"js"</code>

<code>        </code><code>}</code>

看到還原後的JS,你應該猜出onPageletArrive函數是幹嘛的吧,其實onPageletArrive最主要實作就是把"content"中的html内容插入到對應id(上面的"pagelet_welcome_box")的html元素中,并下載下傳對應的css和JS。

三、chunk、flush

      看到上面的分析後,大家一定奇怪,facebook為什麼要生成那麼多段JS,再用js去動态插入html代碼,這不是脫了褲子放屁,多此一舉嗎?還不如直接生成html代碼了。facebook當然不會那麼笨了,讓我們先監控下facebook的http請求,監控圖如下:

      注意上圖中紅色部分,原來facebook使用了chunk對頁面進行分塊輸出。這就比較容易了解了,facebook首頁的js代碼段不是1次就全部輸出的,而是一段一段進行輸出的。

總結

     facebook使用chunk技術讓頁面分塊輸出成很多JS段,這樣做的好處就是伺服器和用戶端可以并行進行處理,不用等伺服器全部處理完畢,用戶端才進行處理。

     舉個部落格園首頁的列子,部落格園首頁分為下面幾塊("推薦部落格排行","首頁随筆清單","最新新聞"...),

     我們一般對該http請求處理如下:

         1. 浏覽器發送http請求

         2. 伺服器處理請求(從緩存讀取前50個推薦部落格,從資料庫讀取"首頁随筆清單",從資料庫讀取"最新新聞"),生成首頁的html代碼。

         3. 伺服器發送html代碼給用戶端

         4、浏覽器接收到響應,處理html(下載下傳css,js,image,執行js等等)

    可以看出傳統的http請求4個過程中,每個過程都必須等待前1個過程完成後才能執行,這樣就存在很大的資源浪費。

    facebook的對該http請求的處理如下:

        1. 浏覽器發送http請求

        2. 伺服器處理請求(從緩存讀取前50個推薦部落格,生成"推薦部落格"的js代碼段,flush輸出該代碼段,

      伺服器繼續讀取"首頁随筆清單",并生成輸入js代碼段。

      伺服器繼續讀取"最新新聞",并生成輸入js代碼段。

        3. 浏覽器接收到js代碼段,下載下傳該代碼段所需的js和css。插入html代碼。

     在這個處理流程中,最大的特點就是2,3是并行進行處理的,伺服器處理完一部分資料就把已經處理好的資料交給浏覽器進行呈現處理,自己再繼續處理其他的資料。

PS:文章看完了,有些同學可能會想,為什麼不像部落格園一樣,前台全部用ajax來異步讀取"推薦部落格" ,“最新新聞”的資料了,這樣做就不會出現因為要處理太多資料而讓用戶端等待太久的問題了。我覺得對于facebook這種并發量巨大的網站,使用這種方法無疑會産生太多的請求,比如facebook首頁用了14個chunk,如果使用ajax,則需要多14個request請求,這将增加不少伺服器的壓力吧。     

本文轉自BearRui(AK-47)部落格園部落格,原文連結:  http://www.cnblogs.com/BearsTaR/archive/2010/06/18/facebook_html_chunk.html  ,如需轉載請自行聯系原作者

繼續閱讀