国产九色porn网址_亚洲综合伊人_91麻豆精品视频_免费吸乳羞羞网站视频

您好,微網(wǎng)歡迎您! 登錄  |  注冊
汕頭公司 |  深圳公司              咨詢熱線:400-830-8248               微網(wǎng)優(yōu)點  |  視頻介紹 |  服務(wù)支持
開店咨詢
咨詢電話:400-830-8248
微網(wǎng)商學院
中國第一微商學院
網(wǎng)絡(luò)商學院
首頁 > 技術(shù)前沿
[淺析]淘寶詳情頁的BigRender優(yōu)化的最佳方式
文章出處:微網(wǎng)  更新時間:2011-11-04  點擊率:
[淺析]淘寶詳情頁的BigRender優(yōu)化的最佳方式

導(dǎo)讀:BigPipe是服務(wù)器chunked輸出html內(nèi)容,BigRender是服務(wù)器一次性輸出的,究竟淘寶商品詳情頁的BigRender方式是如何效仿Facebook的BigPipe方式的?存放大塊HTML代碼的最佳方式又是什么?文中為您揭曉答案。

內(nèi)容如下:

對于復(fù)雜頁面,為了將用戶關(guān)注的內(nèi)容盡可能快渲染出來,至少有兩種方式:

一、Facebook的BigPipe方式。

先輸出頁面整體布局,然后逐步輸出腳本塊,一邊輸出一邊執(zhí)行,將內(nèi)容渲染回頁面布局中。這樣可以讓服務(wù)端的運算、網(wǎng)絡(luò)傳輸和瀏覽器端的渲染變成并行。BigPipe最主要解決的問題是服務(wù)端的運算時間,當服務(wù)端的運算時間大于300~500ms時才能體現(xiàn)出優(yōu)勢。當服務(wù)端響應(yīng)非常快(小于100ms),BigPipe退化為下面要講的BigRender.

二、淘寶商品詳情頁的BigRender方式。

淘寶的商品詳情頁,服務(wù)端平均響應(yīng)時間為52ms,采用BigPipe chunked輸出意義不大。這次優(yōu)化主要在瀏覽器端。頁面下載完畢后,要經(jīng)過Tokenization---Tree Construction—Rendering。要讓首屏盡快出來,得給瀏覽器減輕渲染首屏的工作量。可以從兩方面入手:

減少DOM節(jié)點數(shù)。節(jié)點數(shù)越少,意味著Tokenization, Rendering等操作耗費的時間越少。(對于典型的淘寶商品詳情頁,經(jīng)測試發(fā)現(xiàn),每增加一個DOM節(jié)點,會導(dǎo)致首屏渲染時間延遲約0.5ms.)

減少腳本執(zhí)行時間。腳本執(zhí)行和UI Update共享一個thread,腳本耗的時間越少,UI Update就能越發(fā)提前。

減少首屏DOM節(jié)點數(shù)

對于BigPipe來說,初始輸出的只有頁面布局,DOM節(jié)點數(shù)不多。首屏的DOM節(jié)點數(shù)主要取決于首屏腳本塊中,字符串化的html代碼:

  1. big_pipe.onPageletArrive({ "content": { /* data */ } })   
  2.  

這種方式下,頁面中的DOM節(jié)點是逐步增加的。尚未渲染的DOM節(jié)點,不會影響TTI區(qū)域。

對于BigRender來說,減少DOM節(jié)點數(shù)的方式有:

和Facebook的BigPipe一樣,調(diào)整頁面代碼為頁面布局+腳本塊。BigPipe是服務(wù)器chunked輸出html內(nèi)容,BigRender是服務(wù)器一次性輸出,其他都是一樣的。

盡量少調(diào)整頁面代碼,但通過某種方式,將首屏不需要的html代碼先存放起來。渲染好首屏后,再將存儲好的html代碼逐步渲染出來。

用js字符串來存放html代碼

最容易想到的一種方式是學習Facebook好榜樣,用js字符串來存放:

  1. <script>   
  2.  
  3. var data = "<p>some data</p>...";   
  4.  
  5. </script>   

這種方式對于BigRender來說,并不是很好:

1.由于存放在js字符串變量中,需要對雙引號或單引號轉(zhuǎn)義。

2.由于script是內(nèi)嵌的,需要對script ETAGO轉(zhuǎn)義。

3.服務(wù)器端需要將html代碼轉(zhuǎn)化為一行。(也可以不轉(zhuǎn)成一行,用續(xù)行符來做。)

4.當html代碼中含有script時,需要先去除script中的單行注釋,否則轉(zhuǎn)化成一行時,會出問題。這一步,看似簡單,實際上很不容易,特別是對于淘寶旺鋪這種有第三方代碼的情況。(移除注釋的方法可以參考:Simple but Safe Comment Removal, 使用正則的方式很難做到0 bug,不用正則的話,需要引入html parser和javascript parser,效率更低。)

把代碼規(guī)范做好,把校驗工作做好,再加上預(yù)處理和緩存,js字符串的方式也是非常不錯的。但對于淘寶詳情頁來說,目前用js字符串的方式需要做的改動比較多,增加的服務(wù)器消耗不少,不是很合適。

我們這次優(yōu)化的目標是:

1.大幅度減少首屏渲染時間。

2.盡量不改變原有開發(fā)習慣。

3.用盡量少的代碼做盡量多的優(yōu)化。

用注釋來存放html代碼

為了便于獲取注釋內(nèi)容,添加一層包裹:

  1. <div id="comment-data"><!--   
  2.  
  3. html code   
  4.  
  5. --></div>   

這樣,獲取代碼很簡單:

  1. var htmlCode = document.getElementById('comment-data').  
  2. childNodes[0].nodeValue;  
  3.  

缺點是:

1.服務(wù)端,html中的-->要替換為某種特殊標記。(不能簡單轉(zhuǎn)義為--&gt;)

2.服務(wù)端,html中的--也要替換為某種特殊標記。否則在Firefox低版本中存在bug.

3.瀏覽器端,得到html Code后,要將上面的特殊標記替換回原值。

當html code很大時,替換的效率不高。依賴特殊標記的替換理論上也不完美。

還有什么存放方式呢?

HTML的元素類型

HTML元素分為五大類:

  1. Void elements。像hr,br,base這種。
  2. Raw text elements。有兩個:script和style.
  3. RCDATA elements。也有兩個:textarea和title.
  4. Foreign elements。來自MATHML和SVG的元素。
  5. Normal elements。除了以上四種類型之外的所有元素,比如p,div,iframe等。

顯然,Void elements和Foreign elements不適合用來存放html代碼。

對于Normal elements,里面的<字符會被當做tag open來解析,有一個方式是通過display:none來避免渲染。

  1. <div style="display:none"> 
  2.  
  3. html code   
  4.  
  5. </div>   

這樣做,減少的只是可見的DOM節(jié)點數(shù),DOM總數(shù)依舊不變。Tokenization — Tree Construction等操作的耗時并沒減少。

我們將重點放到Raw text elements和RCDATA elements上來。

CDATA,PCDATA和RCDATA

先了解下CDATA(Character Data) 的相關(guān)知識點。

在XML中,不包含子元素的元素的內(nèi)容默認必須是PCDATA(Parsed Character Data):

  1. <data>&lt;p&gt;some text&lt;/p&gt;</data>   

“Parsed”是指<和&字符要轉(zhuǎn)換成&lt;和&amp;實體字符形式。如果不想寫一大堆&xx;,可以直接標記為CDATA:

  1. <data><![CDATA[<p>some text</p>]]></data>   

這是XML的習慣,很嚴格,但對用戶并不友好。在HTML中,如果要兼容XML,得像如下一樣:

  1.  <script>   
  2.  
  3.  //<![CDATA[   
  4.  
  5.  var t = "<p>";   
  6.  
  7.  //]]>   
  8.  
  9. </script>   
  10.  

增加的<![CDATA]很無聊。script中本就是CDATA.

為了讓用戶更舒心,讓代碼更自然,HTML將script和style定義為Raw text elements。也就是說,這兩個元素里面的內(nèi)容是raw text,里面出現(xiàn)的>就表示>字符本身,不會被當作tag open來解析;&gt;也不會根據(jù)實體字符來轉(zhuǎn)義,就表示&gt;字串自身。這就是CDATA.

Raw text elements有一個限制:里面的內(nèi)容不能有自身的ETAGO標記,也就是說,script里的內(nèi)容不能含有</script(\s|\\|>),否則就會導(dǎo)致script提前結(jié)束:

  1. <script>   
  2.  
  3.  document.write('<script>alert("O HAI")</script>');   
  4.  
  5.  </script> 

上面的代碼會出錯,必須打破&lt/script組合:

  1. <script>   
  2.  
  3. 2 // Using string concatenation:   
  4.  
  5. 3 document.write('<script>alert("heh")<' + '/script>'); // Lame.   
  6.  
  7. 4 // Using a string literal escape:   
  8.  
  9. 5 document.write('<script>alert("huh")<\x3Cscript>'); // Lame.   
  10.  
  11. 6 // Simply escaping the solidus character with a reverse solidus (\):   
  12.  
  13. 7 document.write('<script>alert("O HAI")<\/script>'); // Awesome!   
  14.  
  15. </script>   
  16.  

style也類似,不多說。

除了Raw text elements,還有RCDATA elements。我們來看看。

RCDATA(Replaceable Character Data)表示里面可以有&xx;等實體字符,也可以包含<字符而不會被當作tag open來解析。比如:

  1. 1<textarea><p>&lt;</p></textarea> 
  2.  

在RCDATA里,&lt;可替換為<(Replaceable的含義),拿到值(比如textarea.value)后,是無從得知源碼里是否有&lt;等實體字符的。

用script來存放html代碼

回到正題。在Raw text elements里,可以用script來存放數(shù)據(jù):

  1. <script type="text/html" id="script-data">   
  2.  
  3. <p>some text</p>   
  4.  
  5. </script>   
  6.  

獲取也很簡單:

  1. var htmlCode = document.getElementById('script-data').innerHTML;   

這個方案比用注釋來存放的方案更好,但依舊存在以下缺點:

服務(wù)端,要將script里html中的</script替換為某種特殊標記。

瀏覽器端,得到htmlCode后,要將上面的特殊標記替換回原值。

注意:特殊標記不能是<\/script,因為有可能存在以下代碼:

  1. <script type="text/html" id="script-data">   
  2.  
  3. <script>   
  4.  
  5. 3 var str = '<\/script>';   
  6.  
  7. <\/script>   
  8.  
  9. </script>   
  10.  

這樣替換回原值時,會誤傷str字符串。

用textarea來存放html代碼

textarea中的內(nèi)容會按照RCDATA規(guī)則來解析:

遇到&時,會盡可能得到實體字符。

遇到</textarea(\s|\\|>)時,會結(jié)束解析。

其他都直接作為textarea的內(nèi)容。

  1. <textarea id="area-data">   
  2.  
  3. <p>some text</p>   
  4.  
  5. </textarea>   
  6.  

獲取非常簡單:

  1. 1 var htmlCode = document.getElementById('area-data').value;   
  2.  

缺點:

服務(wù)端,要將html中的&轉(zhuǎn)義成&amp;

服務(wù)端,要打破ETAGO,將</textarea轉(zhuǎn)義成&lt;/textarea

優(yōu)點很明顯,在瀏覽器端,只需通過textarea.value取值即可,無需進行任何轉(zhuǎn)義替換操作。

并且理論上不會出現(xiàn)任何bug.

存放大塊HTML代碼的最佳方式

經(jīng)過上面的分析,結(jié)果已經(jīng)很明顯,用RCDATA elements來存放數(shù)據(jù)是最妥當?shù)摹itle元素明顯不合適,因此最后的選擇就剩下一個了:textarea并且從語義上講,用 text area來存放html text也說得過去。

回到首屏渲染優(yōu)化

可以根據(jù)實際情況,將頁面劃分成幾大區(qū)域。非首屏區(qū)域,簡單轉(zhuǎn)義后,直接用textarea包裹起來。這樣,DOM數(shù)立刻就減少了。瀏覽器在拿到html代碼時,首次 Tokenization — Tree Construction的速度就會大大加快。

完整的優(yōu)化,還需要:

給瀏覽器合理的喘息(UI Update)時間,等首屏真正在顯示器上繪制出來后,再進行下一步操作。

得到textarea.value,填充回DOM樹時,得妥善處理內(nèi)嵌的script代碼。

對內(nèi)嵌script代碼中的document.write要妥善處理。

通過textarea回填,里面的非defer和async腳本會從同步變成異步。要妥善處理依賴關(guān)系,不破壞原有腳本邏輯。

對于優(yōu)化項目來說,完備的測試和監(jiān)控非常重要。

這次還做了AssetsTransfer。用戶第一次訪問時,會將首屏相關(guān)的腳本和樣式內(nèi)嵌,并做預(yù)加載。用戶再次訪問時,則改成外鏈方式,這樣能充分利用瀏覽器緩存,并減少 html傳輸量。

最后,給一張優(yōu)化成果圖: 

這是一個典型的淘寶詳情頁的首屏時間趨勢圖。可看出,首屏時間從優(yōu)化前的3s降低到了優(yōu)化后的1.5s左右,快了一倍!

更深度的優(yōu)化需要對頁面內(nèi)容(包括腳本)做進一步的細粒度模塊化,區(qū)分出優(yōu)先級,然后根據(jù)需求,靈活自由地控制各個模塊的下載和執(zhí)行等等。

這篇博客寫得比較雜,關(guān)于BigRender優(yōu)化的更多細節(jié),以后有機會再細說。歡迎反饋、拍磚。歡迎業(yè)界各位朋友嘗試BigRender優(yōu)化,希望國內(nèi)的站點速度都越來越快!


聲明:本網(wǎng)部份文章為轉(zhuǎn)載文章,在每篇文章底部有說明,文章的觀點和立場僅代表作者個人立場,不代表微網(wǎng)立場,若是文章轉(zhuǎn)載中有侵范您的權(quán)益,請發(fā)郵件到 493149@qq.com或致電13922854199通知刪除,謝謝!

QQ咨詢  技術(shù)總監(jiān)  微網(wǎng)顧問  陳經(jīng)理  渠道經(jīng)理  

免費電話 免費熱線:400-830-8248  

微信咨詢  

注冊開店

代理加盟

返回頂部