javascript
javascript的性能优化
(1)?如何加載JS,JS文件應放在什么位置?
外部JS的阻塞下載?
?????所有瀏覽器在下載JS的時候,會阻止一切其他活動,比如其他資源的下載,內容的呈現等等。至到JS下載、解析、執行完畢后才開始繼續并行下載其他資源并呈現內容。?
????有人會問:為什么JS不能像CSS、image一樣并行下載了?這里需要簡單介紹一下瀏覽器構造頁面的原理,?
?當 瀏覽器從服務器接收到了HTML文檔,并把HTML在內存中轉換成DOM樹,在轉換的過程中如果發現某個節點(node)上引用了CSS或 者?IMAGE,就會再發1個request去請求CSS或image,然后繼續執行下面的轉換,而不需要等待request的返回,當request返 回后,只需要把返回的內容放入到DOM樹中對應的位置就OK。但當引用了JS的時候,瀏覽器發送1個js?request就會一直等待該request的 返回。因為瀏覽器需要1個穩定的DOM樹結構,而JS中很有可能有代碼直接改變了DOM樹結構,比如使 用?document.write?或?appendChild,甚至是直接使用的location.href進行跳轉,瀏覽器為了防止出現JS修改 DOM樹,需要重新構建DOM樹的情況,所以就會阻塞其他的下載和呈現.?
嵌入JS是指直接寫在HTML文檔中的JS代碼。上面說了引用外 部的JS會阻塞其后的資源下載和其后的內容呈現,哪嵌入的JS又會是怎樣阻塞的了,拿兩段代碼運行后,對比。會發現代碼1中,在前5秒中頁面上是一篇空 白,5秒中后頁面全部顯示。?代碼2中,前5秒中blogjava,csdn等先顯示出來,5秒后MSN才顯示出來。?
?????可以看出嵌入JS會阻塞所有內容的呈現,而外部JS只會阻塞其后內容的顯示,2種方式都會阻塞其后資源的下載。?
????根本原因:因為瀏覽器會維持html中css和js的順序,樣式表必須在嵌入的JS執行前先加載、解析完。而嵌入的JS會阻塞后面的資源加載,所以就會出現上面CSS阻塞下載的情況。?
??
嵌入JS應該放在什么位置?
???1、放在底部,雖然放在底部照樣會阻塞所有呈現,但不會阻塞資源下載。?
????
???2、如果嵌入JS放在head中,請把嵌入JS放在CSS頭部。?
????
???3、使用defer?
????
???4、不要在嵌入的JS中調用運行時間較長的函數,如果一定要用,可以用setTimeout來調用?
(2)?為什么要減少請求數,如何減少請求數!?
http連接的開銷?
???相比request頭部多余的數據,http連接的開銷則更加嚴重。先看看從用戶輸入1個URL到下載內容到客戶端需要經過哪些階段:?
???1.?域名解析?
???2.?開啟TCP連接??
???3.?發送請求??
???4.?等待(主要包括網絡延遲和服務器處理時間)?
???5.?下載資源?
????
????可能很多人認為每次請求大部分時間都花在下載資源上,讓我們看看blogjava資源下載瀑布圖(每種顏色代表的階段與上面5個階段對應):?
如何減少請求數?
???
1、合并文件?
??????合并文件就是把很多JS文件合并成1個文件,很多CSS文件合并成1個文件,這種方法應該很多人用到過,這里不做詳細介紹,?
?????只推薦1個合并的工具:yuiCompressor?這個工具yahoo提供的。?http://developer.yahoo.com/yui/compressor/?
???
2、合并圖片?
??????這是利用css?sprite,通過控制背景圖片的位置來顯示不同的圖片。這種技術也是大家都用過的,不做詳細介紹,推薦1個在線合并圖片的網站:http://csssprites.com/?
??????
3、把JS、CSS合并到1個文件?
??????上面第1種方法說的只是把幾個JS文件合并成1個JS文件,幾個CSS文件合并成1個CSS文件,哪如何把CSS和JS都合并到1個文件中.?
??????
4、使用Image?maps?
??????Image?maps?是把多個圖片合并成1個圖片,然后使用html中的<map>標簽連接圖片,并實現點擊圖片不同的區域執行不同的動作,image?map在導航條中比較容易使用到。?
?????image?map的使用方法見:?http://www.w3.org/TR/html401/struct/objects.html#h-13.6?
???
??5、data嵌入圖片?
項目中的處理方案:?
???????
?????為了解決上面討論過的問題,在下寫了1個如下的組件,組件中根據我們自己的實際情況使用了文件大小來做為文件的版本號,雖然在文件修改很小(比如把字符a改成b),可能文件大小并沒有變,導致版本號也不會變。?
但這種機率還是非常低的。當然如果你覺的使用文件修改時間作為版本號適合你,只需要修改一行代碼就行,下面看下這個組件的處理流程(本來想用流程圖表達,最后還是覺的文字來的直白寫):?
????1.?程序啟動(contextInitialized)?
??
????2.?搜索程序目錄下的所有merge.txt文件,根據merge.txt文件的配置合并文件,?merge.txt文件實例如下:?
????#?文件合并配置文件,多個文件以|隔開,以/開頭的表示從根目錄開始,??
????#?空格之后的文件名表示合并之后的文件名?
????#?把1,2,3合并到all文件中?
????1.js|2.js|3.js?all.js?
????#合并CSS?
????/css/mian.css|/css/common.css?all.css?
????3.?搜索程序目錄下所有JS,CSS文件(包括合并后的),每個文件都壓縮后生成對應的1個新文件。?
????4.?搜索程序目錄下所有JSP,html文件,把所有JS,css的引用代碼改成壓縮后并加了版本號的引用。?
(3)?減少請求,響應的數據量?
如何減少請求、響應的數據量(即在網絡中傳輸的數據量),減少傳輸的數據量不僅僅可以加快頁面加載速度,更可以節約服務器帶寬,為你剩不少錢(好像很多機房托管都是按流量算錢的)。?
GZIP壓縮?
?????gzip是目前所有瀏覽器都支持的一種壓縮格式,IE6需要SP1及以上才支持(別說你還在用IE5,~_~)。gzip可以說是最方便而且也是最大減少響應數據量的1種方法。?
說它方便,是因為你不需要為它寫任何額外的代碼,只需要在http服務器上加上配置都行了,現在主流的http服務器都支持gzip,各種服務器的配置這里就不一一介紹(其實是我不知道怎么配),?
別對圖片啟用gzip?
????在知道了gzip強大的壓縮能力后,你是否想對服務器上的所有文件啟用gzip了,先讓我們看看圖片中啟用gzip后會是什么情況。?
比較適合啟用gzip壓縮的文件有如下這些:?
????1.?javascript?
????2.?CSS?
????3.?HTML,xml?
????4、plain?text?
別亂用cookie?
??????現 在幾乎沒有哪個網站不使用cookie了,可是該怎么使用cookie比較合適了,cookie有幾個重要的屬性:path(路 徑),domain(域),expires(過期時間)。瀏覽器就是根據這3個屬性來判斷在發送請求的時候是否需要帶上這個cookie。
??????cookie使用最好的方式,就是當請求的資源需要cookie的時候才帶上該cookie。其他任何請求都不帶上cookie。
妙用204狀態?
?????http 中200,404,500狀態大家都很清楚,但204狀態大家可能用的比較少,204狀態是指服務器成功處理了客戶端請求,但服務器無返回內容。204是 HTTP中數據量最少的響應狀態,204的響應中沒有body,而且Content-Length=0。很多人在使用ajax提交一些數據給服務器,而不 需要服務器返回的時候,常常在服務端使用下面的代碼:response.getWriter().print(""),這是返回1個空白的頁面,是1個 200請求。它還是有body,而且Content-Length不會等于0。其實這個時候你完全可以直接返回1個204狀 態?(response.setStatus(204))。?
(4)?如何加載google-analytics(或其他第三方)的JS?
?????很 多網站為了獲取用戶訪問網站的統計信息,使用了google-analytics或其他分析網站(下面的討論中只提google- analytics,?簡稱ga)。注冊ga后,ga就會生成一段js腳本,很多人直接把這段js復制到<body>的最后面就完事(包 括?博客園、CSDN、BlogJava)。可是ga自動生成的這段JS真的就是最合理的嗎??
??????哪怎么樣才算是合理,怎樣才是不合理了?因ga只是1個分析工具,它的使用絕對不能影響到我們的程序,如果影響了,則是不合理的。不影響則是合理的。?
使用document.write來加載JS,注意了,這樣加載js是阻塞加載的,就是這個js沒加載完,后面的所有資源和JS都不能下載和執行。可能你會覺的這段代碼在body的最后面,后沒已經沒內容,沒什么會阻塞的了。?
??????還 有一些你忽略了,相信很多人在寫JS的時候需要在頁面加載完畢后執行一些JS或AJAX,一般寫在window.onload?事件,或者寫入 jquery的$(document).ready()方法中。這些JS就會被阻塞。如果我們的頁面上很多數據在?window.onload中使用 AJAX加載,而偏偏這個時候ga因為某些原因(和諧和諧)不能訪問,或者訪問很慢的時候。問題就來,我們自己的JS一直在等待ga的JS加載完,只有等 ga的js加載超時后才會執行我們的JS。?
(5)?瘋狂的HTML壓縮?
(6)?頁面呈現、重繪、回流。?
頁面呈現流程?
?????在討論頁面重繪、回流之前。需要對頁面的呈現流程有些了解,頁面是怎么把html結合css等顯示到瀏覽器上的,下面的流程圖顯示了瀏覽器對頁面的呈現的處理流程。可能不同的瀏覽器略微會有些不同。但基本上都是類似的。?
????1.??瀏 覽器把獲取到的html代碼解析成1個Dom樹,html中的每個tag都是Dom樹中的1個節點,根節點就是我們常用的document對 象?(<html>?tag)。dom樹就是我們用firebug或者IE?Developer?Toolbar等工具看到的html結構, 里面包含了所有的html?tag,包括display:none隱藏,還有用JS動態添加的元素等。?
?????2.?瀏覽器把所有樣式(主要包括css和瀏覽器的樣式設置)解析成樣式結構體,在解析的過程中會去掉瀏覽器不能識別的樣式,比如IE會去掉-moz開頭的樣式,而firefox會去掉_開頭的樣式。?
?????3、 dom?tree和樣式結構體結合后構建呈現樹(render?tree),render?tree有點類似于dom?tree,但其實區別有很 大,render?tree能識別樣式,render?tree中每個node都有自己的style,而且render?tree不包含隱藏的節點(比如 display:none的節點,還有head節點),因為這些節點不會用于呈現,而且不會影響呈現的,所以就不會包含到?render?tree中。注 意?visibility:hidden隱藏的元素還是會包含到render?tree中的,因為visibility:hidden?會影響布局 (layout),會占有空間。根據css2的標準,render?tree中的每個節點都稱為box(Box?dimensions),box所有屬 性:width,height,margin,padding,left,top,border等。?
????4.?一旦render?tree構建完畢后,瀏覽器就可以根據render?tree來繪制頁面了。?
回流與重繪?
????1.?當render?tree中的一部分(或全部)因為元素的規模尺寸,布局,隱藏等改變而需要重新構建。這就稱為回流(其實我覺得叫重新布局更簡單明了些)。每個頁面至少需要一次回流,就是在頁面第一次加載的時候。?
????2.?當render?tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響布局的,比如background-color。則就叫稱為重繪。?
??注:從上面可以看出,回流必將引起重繪,而重繪不一定會引起回流。?
什么操作會引起重繪、回流?
????
????其實任何對render?tree中元素的操作都會引起回流或者重繪,比如:?
????1.?添加、刪除元素(回流+重繪)?
????2.?隱藏元素,display:none(回流+重繪),visibility:hidden(只重繪,不回流)?
????3.?移動元素,比如改變top,left(jquery的animate方法就是,改變top,left不一定會影響回流),或者移動元素到另外1個父元素中。(重繪+回流)?
????4.?對style的操作(對不同的屬性操作,影響不一樣)?
????5.?還有一種是用戶的操作,比如改變瀏覽器大小,改變瀏覽器的字體大小等(回流+重繪)?
如何減少回流、重繪?
????減少回流、重繪其實就是需要減少對render?tree的操作,并減少對一些style信息的請求,盡量利用好瀏覽器的優化策略。具體方法有:?
????1.?不要1個1個改變元素的樣式屬性,最好直接改變className,但className是預先定義好的樣式,不是動態的,如果你要動態改變一些樣式,則使用cssText來改變?
2.?讓要操作的元素進行"離線處理",處理完后一起更新,這里所謂的"離線處理"即讓元素不存在于render?tree中,比如:?
?????????a)?使用documentFragment或div等元素進行緩存操作,這個主要用于添加元素的時候,大家應該都用過,就是先把所有要添加到元素添加到1個div(這個div也是新加的),?
????????????最后才把這個div?append到body中。?
?????????b)?先display:none?隱藏元素,然后對該元素進行所有的操作,最后再顯示該元素。因對display:none的元素進行操作不會引起回流、重繪。所以只要操作只會有2次回流。?
???3?不要經常訪問會引起瀏覽器flush隊列的屬性,如果你確實要訪問,就先讀取到變量中進行緩存,以后用的時候直接讀取變量就可以了?
4.?考慮你的操作會影響到render?tree中的多少節點以及影響的方式,影響越多,花費肯定就越多。?
(6)?了解CSS的查找匹配原理,讓CSS更簡潔、高效?
匹配原理:?
?????瀏覽器CSS匹配不是從左到右進行查找,而是從右到左進行查找。比如之前說的?DIV#divBox?p?span.red{color:red;},瀏覽器的查找順序如下:?
先查找html中所有class='red'的span元素,找到后,再查找其父輩元素中是否有p元素,再判斷p的父元素中是否有id為divBox的div元素,如果都存在則匹配上。?
簡潔、高效的CSS:?
???????所謂高效的CSS就是讓瀏覽器在查找style匹配的元素的時候盡量進行少的查找,下面列出一些我們常見的寫CSS犯一些低效錯誤(也是我以前常常犯的錯誤,還老以為這樣寫才是高效的):?
????
??1.不要在ID選擇器前使用標簽名?
?一般寫法:DIV#divBox?
?更好寫法:#divBox?
?解釋:?因為ID選擇器是唯一的,加上div反而增加不必要的匹配。?
???
??2.不要再class選擇器前使用標簽名?
?一般寫法:span.red?
?更好寫法:.red?
??解釋:?同第一條,但如果你定義了多個.red,而且在不同的元素下是樣式不一樣,則不能去掉,比如你css文件中定義如下:?
?????p.red{color:red;}?
?????span.red{color:#ff00ff}?
?????如果是這樣定義的就不要去掉,去掉后就會混淆,不過建議最好不要這樣寫?
??3.盡量少使用層級關系?
?一般寫法:#divBox?p?.red{color:red;}???????
?更好寫法:.red{..}?
???
??4.使用class代替層級關系?
?一般寫法:#divBox?ul?li?a{display:block;}???????
?更好寫法:.block{display:block;}
?
感覺可以,值得學習一下,就轉了。轉自www.zhihaijiangku.com
?
轉載于:https://www.cnblogs.com/zhilelele/p/8026585.html
總結
以上是生活随笔為你收集整理的javascript的性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 配置 Docker 加速器
- 下一篇: Centos 6.5部署nginx+uw