Web性能優化

一.css性能優化 摘自http://www.ibm.com/developerworks/cn/web/1109_zhouxiang_optcss/

1.把 Stylesheets 放在 HTML 頁面頭部:

瀏覽器在所有的 stylesheets 加載完成之後,纔會開始渲染整個頁面,在此之前,瀏覽器不會渲染頁面裏的任何內容,頁面會一直呈現空白。這也是爲什麼要把 stylesheet 放在頭部的原因。如果放在 HTML 頁面底部,頁面渲染就不僅僅是在等待 stylesheet 的加載,還要等待 html 內容加載完成,這樣一來,用戶看到頁面的時間會更晚。

對於 @import 和 <link> 兩種加載外部 CSS 文件的方式:@import 就相當於是把 <link> 標籤放在頁面的底部,所以從優化性能的角度看,應該儘量避免使用 @import 命令

2.避免使用 CSS Expressions:

 CSS Expression 案例
 Background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" )

Expression 只有 IE 支持,而且他的執行比大多數人想象的要頻繁的多。不僅頁面渲染和改變大小 (resize) 時會執行,頁面滾動 (scroll) 時也會執行,甚至連鼠標在頁面上滑動時都會執行。在 expression 裏面加上一個計數器就會知道,expression 的執行上相當頻繁的。鼠標的滾動很容易就會使 expression 的執行次數超過 10000。

避免使用 Filter:

IE 特有的 AlphaImageLoader filter 是爲了解決 IE6 及以前版本不支持半透明的 PNG 圖片而存在的。但是瀏覽器在下載 filter 裏面的圖片時會“凍結”瀏覽器,停止渲染頁面。同時 filter 也會增大內存消耗。最不能忍受的是 filter 樣式在每個頁面元素(使用到該 filter 樣式)渲染時都會被瀏覽器分析一次,而不是像一般的背景圖片渲染模式:使用過該背景圖片的所有元素都是被瀏覽器一次性渲染的。

針對這種情況,最好的解決辦法就是使用 PNG8。

3.CSS 縮寫:

CSS 縮寫可以讓你用極少的代碼定義一系列樣式屬性,這種做法可以極大程度的縮減代碼量以達到提高性能的目的。

 Colour 縮寫
 #000000     ------>>     #000 
 #336699     ------>>     #369

關於顏色,重複的屬性值可以省略。

 各種縮寫方式
 Margin-top: 2px; 
 Margin-right: 5px; 
 Margin-bottom: 2em; 
 Margin-left: 15px;     ----->>     Margin: 2px 5px 2em 15px; 

 Border-width: 1px; 
 Border-style: solid; 
 Border-color: #000     ----->>     border: 1px solid #000 

 Font-style: italic; 
 Font-variant: small-caps; 
 Font-weight: bold; 
 Font-size: 1em; 
 Line-height: 140%; 
 Font-family: sans-serif;  ----->>  font: italic small-caps bold 1em 140% sans-serief 

 Background-color: #f00; 
 Background-image: url(background.gif); 
 Background-repeat: no-repeat; 
 Background-attachment: fixed; 
 Background-position: 0 0; 
  ----->>background: #f00 url(background.gif) no-repeat fixed 0 0 

 list-style-type: square; 
 list-style-position: inside; 
 List-style-image: url(image.gif)  ----->> list-style: square inside url(image.gif)

4.Multiple Declarations

關於 CSS 的 class 聲明和定義,也有簡寫的方式

 Class 的聲明
.Class1{position: absolute; left: 20px; top: 30px;} 
.Class2{position: absolute; left: 20px; top: 30px;} 
.Class3{position: absolute; left: 20px; top: 30px;} 
.Class4{position: absolute; left: 20px; top: 30px;} 
.Class5{position: absolute; left: 20px; top: 30px;} 
.Class6{position: absolute; left: 20px; top: 30px;} 

 -------------------->>>>>>> 

 .class1 .class2 .class3 .class4 .class5 .class6{ 
 Position: absolute; left: 20px; top: 20px; 
 }

這種 Class 簡寫的方式可以極大的縮減我們的代碼,提高瀏覽器分析識別的效率。

5. CSS 選擇器 (CSS Selectors)

Child selector

 #toc > li {font-weight: bold}

按照我們慣常的理解,編譯器應該是先查找 id 爲“toc”的節點,然後在他的所有直接子節點中查找類型(tag)爲“li”的節點,將“font-weight”屬性應用到這些節點上。

但是,不幸的是,恰恰相反,瀏覽器是“從右往左”來分析 class 的,它的匹配規則是從右向左來進行匹配的。這裏,瀏覽器首先會查找頁面上所有的“li”節點,然後再去做進一步的判斷:如果它的父節點的 id 爲“toc”,則匹配成功。

Descendant selector
 #toc  li {font-weight: bold}

這個效率比之前的“child selector”效率更慢,而且要慢很多。瀏覽器先便利所有的“li”節點,然後步步上溯其父節點,直到 DOM 結構的根節點(document),如果有某個節點的 id 爲“toc”,則匹配成功,否則繼續查找下一個“li”節點。

 儘量避免 universal rules
 [hidden="true"] { ... } /* A universal rule */

這裏的匹配規則很明顯:查找頁面上的所有節點,如果有節點存在“hidden”屬性,並且其屬性值爲“true”,則匹配成功。這是最耗時耗力的匹配,頁面上的所有節點都需要進行匹配運算,這種規則應儘量避免。

 Id-categorized 規則與 tag name 或 class 規則並行
 button#goButton {...};----->>#goButton 
 .fundation#testIcon {...};----->>#testIcon

這裏,按照我們常規的理解,箭頭左邊的寫法似乎是應該更快的,因爲它的限制更多。其實不然,id 是全局唯一的,在匹配 CSS 選擇器時瀏覽器定位到 id 是最快的,如果伴隨有其他的非 id 的 selector,反而會影響匹配的效率。

關於 class-categorized 規則
 button.indented {...}----->>.button-indented {...}

程序員們經常會給某個 Class 前面加上標籤名稱(Tag Name),以更精確且快速的定位該節點,但是這樣往往效率更差。和清單 8 中的原理一樣,頁面上的 class 在全局範圍內來講應該是唯一的,用唯一的 Class 名稱來定位一個節點往往比組合定位更加快捷。事實上,這種做法也可以避免由於開發修改頁面元素的類型(Tag)而導致的樣式失效的情況,做到樣式與元素的分離,兩者獨立維護。

 儘量減少規則數量
 Span[mailfolder="true"] > table > tr > td.columnClass {...} 

 ------------------->>>>>>> 

 .span-mailfolder-tbl-tdCol {...}

規則越多,匹配越慢,上面一種規則需要進行 6 項匹配,先找“columnClass”,再找“td”,然後是“tr”,“table”,最後是符合“mailfolder”爲“true”的 span,這種效率是非常慢的。如果用一個比較特殊的 class 替代(span-mailfolder-tbl-tdCol),效率會快上好幾倍。

.儘量避免使用 descendant selector
 treehead treerow treecell {...} ----->> treehead > treerow > treecell {...}

Descendant 選擇器是耗時相對高的選擇器,通常來講,它在 CSS 裏的使用應該是儘量避免的,如果能用 child 選擇器替代就應該儘量這樣去做。

利用 CSS 的繼承機制
 Color 
 Font 
 Letter-spacing 
 Line-height 
 List-style 
 Text-align 
 Text-indent 
 Text-transform 
 White-space 
 Word-spacing 

 #bookmark  > .menu-left {list-style-image: url(blah)} 

 ------------>>>>>>>> 

 #bookmark  {list-style-image: url(blah)}

在 CSS 中,有很多 CSS 的屬性以可以繼承的,如果某個節點的父節點已經設定了上述的 CSS 樣式(如:color, font 等 ...),並且子節點無需更改該樣式,則無需再作相關設定,同時,也可以利用這一點:如果很多子節點都需要設定該 CSS 屬性值,可以統一設定其父節點的該 CSS 屬性,這樣一來,所有的子節點再無需做額外設定,加速了 CSS 的分析效率。

二.js優化 摘自http://www.chinaz.com/web/2015/0626/417391.shtml

1. 定義局部變量

因爲局部變量在這條鏈的起端,所以查找局部變量總是比查找全局變量要塊。所以當你想要不止一次地使用一個全局變量的時候,你應該將它定義成局部變量,就像這樣:

var blah = document.getElementById('myID'),
blah2 = document.getElementById('myID2');

改寫成

var doc = document,
blah = doc.getElementById('myID'),
blah2 = doc.getElementById('myID2');

2. 不要使用 with() 語句

這是因爲 with() 語句將會在作用域鏈的開始添加額外的變量。額外的變量意味着,當任何變量需要被訪問的時候,JavaScript引擎都需要先掃描with()語句產生的變量,然後纔是局部變量,最後是全局變量。 So with() essentially gives local variables all the performance drawbacks of global ones, and in turn derails Javascript optimization. 因此with()語句同時給局部變量和全局變量的性能帶來負面影響,最終使我們優化JavaScript性能的計劃破產。

3. 小心使用閉包

閉包基本上被認爲是JavaScript中的new,當我們定義一個即時函數的時候,我們就使用了閉包,比如:

document.getElementById('foo').onclick = function(ev) { };

閉包的問題在於:根據定義,在它們的作用域鏈中至少有三個對象:閉包變量、局部變量和全局變量。這些額外的對象將會導致第1和第2個建議中提到的性能問題。

但是我認爲Nicholas並不是要我們因噎廢食,閉包對於提高代碼可讀性等方面還是非常有用的,只是不要濫用它們(尤其在循環中)。

4. 對象屬性和數組元素的速度都比變量慢

談到JavaScript的數據,一般來說有4種訪問方式:數值、變量、對象屬性和數組元素。在考慮優化時,數值和變量的性能差不多,並且速度顯著優於對象屬性和數組元素。

因此當你多次引用一個對象屬性或者數組元素的時候,你可以通過定義一個變量來獲得性能提升。(這一條在讀、寫數據時都有效)

雖然這條規則在絕大多數情況下是正確的,但是Firefox在優化數組索引上做了一些有意思的工作,能夠讓它的實際性能優於變量。但是考慮到數組元素在其他瀏覽器上的性能弊端,還是應該儘量避免數組查找,除非你真的只針對於火狐瀏覽器的性能而進行開發。

5. 不要在數組中挖得太深

另外,程序員應該避免在數組中挖得太深,因爲進入的層數越多,操作速度就越慢。

簡單地說,在嵌套很多層的數組中操作很慢是因爲數組元素的查找速度很慢。試想如果操作嵌套三層的數組元素,就要執行三次數組元素查找,而不是一次。

因此如果你不斷地引用 foo.bar, 你可以通過定義 var bar = foo.bar 來提高性能。

6. 避免 for-in 循環(和基於函數的迭代)

這是另一條非常教條的建議:不要使用for-in循環。

這背後的邏輯非常直接:要遍歷一個集合內的元素,你可以使用諸如for循環、或者do-while循環來替代for-in循環,for-in循環不僅僅可能需要遍歷額外的數組項,還需要更多的時間。

爲了遍歷這些元素,JavaScript需要爲每一個元素建立一個函數,這種基於函數的迭代帶來了一系列性能問題:額外的函數引入了函數對象被創建和銷燬的上下文,將會在作用域鏈的頂端增加額外的元素。

7. 在循環時將控制條件和控制變量合併起來

提到性能,在循環中需要避免的工作一直是個熱門話題,因爲循環會被重複執行很多次。所以如果有性能優化的需求,先對循環開刀有可能會獲得最明顯的性能提升。

一種優化循環的方法是在定義循環的時候,將控制條件和控制變量合併起來,下面是一個沒有將他們合併起來的例子:

for ( var x = 0; x < 10; x++ ) {
};

當我們要添加什麼東西到這個循環之前,我們發現有幾個操作在每次迭代都會出現。JavaScript引擎需要:

#1:檢查 x 是否存在
#2:檢查 x 是否小於 0 <span style="color: #888888;">(譯者注:我猜這裏是作者的筆誤)</span>
#3:使 x 增加 1

然而如果你只是迭代元素中的一些元素,那麼你可以使用while循環進行輪轉來替代上面這種操作:

var x = 9;
do { } while( x-- );

如果你想更深入地瞭解循環的性能,Zakas提供了一種高級的循環優化技巧,使用異步進行循環(碉堡了!)

8. 爲HTML集合對象定義數組

JavaScript使用了大量的HTML集合對象,比如 document.forms,document.images 等等。通常他們被諸如 getElementsByTagName、getElementByClassName 等方法調用。

由於大量的DOM selection操作,HTML集合對象相當的慢,而且還會帶來很多額外的問題。正如DOM標準中所定義的那樣:“HTML集合是一個虛擬存在,意味着當底層文檔被改變時,它們將自動更新。”這太可怕了!

儘管集合對象看起來跟數組很像,他們在某些地方卻區別很大,比如對於特定查詢的結果。當對象被訪問進行讀寫時,查詢需要重新執行來更新所有與對象相關的組分,比如 length。

HTML集合對象也非常的慢,Nicholas說好像在看球的時候對一個小動作進行60倍速慢放。另外,集合對象也有可能造成死循環,比如下面的例子:

var divs = document.getElementsByTagName('div');
 
for (var i=0; i < divs.length; i++ ) {
    var div = document.createElement("div"); 
    document.appendChild(div);
}

這段代碼造成了死循環,因爲 divs 表示一個實時的HTML集合,並不是你所期望的數組。這種實時的集合在添加 <div> 標籤時被更新,所以i < div.length 永遠都不會結束。

解決這個問題的方法是將這些元素定義成數組,相比只設置 var divs = document.getElementsByTagName(‘div’) 稍微有點麻煩,下面是Zakas提供的強制使用數組的代碼:

function array(items) {
    try {
        return Array.prototype.concat.call(items);
    } catch (ex) {
 
        var i       = 0,
            len     = items.length,
            result  = Array(len);
 
        while (i < len) {
            result[i] = items[i];
            i++;
        }
 
        return result;
    }
}
 
var divs = array( document.getElementsByTagName('div') );
 
for (var i=0l i < divs.length; i++ ) {
    var div = document.createElement("div"); 
    document.appendChild(div);
}

9. 不要碰DOM!

不使用DOM是JavaScript優化中另一個很大的話題。經典的例子是添加一系列的列表項:如果你把每個列表項分別加到DOM中,肯定會比一次性加入所有列表項到DOM中要慢。這是因爲DOM操作開銷很大。

Zakas對這個進行了細緻的講解,解釋了由於迴流(reflow)的存在,DOM操作是非常消耗資源的。迴流通常被理解爲瀏覽器重新選渲染DOM樹的處理過程。比如說,如果你用JavaScript語句改變了一個div的寬度,瀏覽器需要重繪頁面來適應變化。

任何時候只要有元素被添加到DOM樹或者從DOM樹移除,都會引發迴流。使用一個非常方便的JavaScript對象可以解決這個問題——documentFragment,我並沒有使用過,但是在Steve Souders也表示同意這種做法之後我感覺更加肯定了。 

DocumentFragment 基本上是一種瀏覽器以非可視方式實現的類似文檔的片段,非可視化的表現形式帶來了很多優點,最主要的是你可以在 documentFragment 中添加任何結點而不會引起瀏覽器迴流。

10. 修改CSS類,而不是樣式

你也許聽說過:修改CSS類必直接修改樣式會更高效。這歸結於迴流帶來的另一個問題:當佈局樣式發生改變時,會引發迴流。

佈局樣式意味着任何影響改變佈局的變化都會強制引起瀏覽器迴流。比如寬度、高度、字號、浮動等。

但是別誤會我的意思,CSS類並不會避免迴流,但是可以將它的影響最小化。相比每次修改樣式都會引起迴流,使用CSS類一次修改多個樣式,只需要承擔一次迴流帶來的消耗。

因此在修改多個佈局樣式的時候,使用CSS類來優化性能是明智的選擇。另外如果你需要在運行時定義很多歌CSS類,在DOM上添加樣式結點也是不錯的選擇。

三.html優化 摘自http://blog.sina.com.cn/s/blog_946e7651010151j6.html

1,頁面減肥
頁面的肥瘦是影響加載速度最重要的因素
刪除不必要的空格、註釋
將inline的script和css移到外部文件
可以使用HTML Tidy來給HTML減肥,還可以使用一些壓縮工具來給JavaScript減肥

2,減少文件數量
減少頁面上引用的文件數量可以減少HTTP連接數
許多JavaScript、CSS文件可以合併最好合並,人家財幫子都把自己的JavaScriptfunctions和Prototype.js合併到一個base.js文件裏去了

3,減少域名查詢
DNS查詢和解析域名也是消耗時間的,所以要減少對外部JavaScript、CSS、圖片等資源的引用,不同域名的使用越少越好

4,緩存重用數據
使用緩存吧

5,優化頁面元素加載順序
首先加載頁面最初顯示的內容和與之相關的JavaScript和CSS
然後加載DHTML相關的東西
像什麼不是最初顯示相關的圖片、flash、視頻等很肥的資源就最後加載

6,減少inline JavaScript的數量
瀏覽器parser會假設inline JavaScript會改變頁面結構,所以使用inlineJavaScript開銷較大
不要使用document.write()這種輸出內容的方法,使用現代W3C DOM方法來爲現代瀏覽器處理頁面內容

7,使用現代CSS和合法的標籤
使用現代CSS來減少標籤和圖像,例如使用現代CSS+文字完全可以替代一些只有文字的圖片
使用合法的標籤避免瀏覽器解析HTML時做“error correction”等操作,還可以被HTML Tidy來給HTML減肥

8,Chunk your content
不要使用嵌套tables

代碼

1.  <table>  

2.    <table>  

3.     <table>  

4.       ..  

5.     <table>  

6.    <table>  

7.  <table>  


而使用非嵌套tables或者divs

代碼

1.  <table>...</table> 

2.  <table>...</table> 

3.  <table>...</table> 


將基於大塊嵌套的tables的layout分解成小tables,這樣顯示時不用加載整個頁面(或大table)的內容

9,指定圖像和tables的大小
如果瀏覽器可以立即決定圖像或tables的大小,那麼它就可以馬上顯示頁面而不要重新做一些佈局安排的工作
這不僅加快了頁面的顯示,也預防了頁面完成加載後佈局的一些不當的改變
image使用height和width
table使用table-layout: fixed並使用col和colgroup標籤指定columns的width

10,根據用戶瀏覽器明智的選擇策略
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章