前端如何進行網站性能優化
發布時間:2022-03-04 17:04 瀏覽次數:次
大家好,我是IT修真院學員,一枚正直純潔善良的WEB程序員,今天給大家分享一下,修真院官網JS任務4,深度思考中的知識點-前端如何進行網站性能優化。
一、背景介紹
性能優化的目的
1.從用戶角度而言,優化能夠讓頁面加載得更快,對用戶的操作響應得更及時,能夠給用戶提供更為友好的體驗。
2.從服務商角度而言,優化能夠減少頁面請求數,或者減小請求所占帶寬,能夠節省可觀的資源。
二、知識剖析
前端優化的途徑有很多,按粒度大致可以分為兩類,第一類是頁面級別的優化,例如HTTP請求數,腳本的無阻塞加載,內聯腳本的位置優化等;第二類則是代碼級別的優化,例如使用Javascript中的DOM操作優化,CSS選擇符優化,圖片優化以及HTML結構優化等等。
1、頁面級優化
1.1 減少HTTP請求數
(1)設計從實現層面簡化頁面
如果你的頁面像百度首頁一樣簡單,那么接下來的規則基本上都用不著了。保持頁面簡潔、減少資源的使用時最直接的。如果不是這樣,你的頁面需要華麗的皮膚,則繼續閱讀下面的內容。 皮膚,則繼續閱讀下面的內容
(2)合理設置HTTP緩存
緩存的力量是強大的,恰當的緩存設置可以大大的減少 HTTP請求。以有啊首頁為例,當瀏覽器沒有緩存的時候訪問一共會發出 78個請求,共 600多 K數據 (如圖 1.1),而當第二次訪問即瀏覽器已緩存之后訪問則僅有 10個請求,共 20多 K數據 (如圖 1.2)。 (這里需要說明的是,如果直接 F5刷新頁面的話效果是不一樣的,這種情況下請求數還是一樣,不過被緩存資源的請求服務器是 304響應,只有 Header沒有Body ,可以節省帶寬 )
怎樣才算合理設置 ?原則很簡單,能緩存越多越好,能緩存越久越好。例如,很少變化的圖片資源可以直接通過 HTTP Header中的Expires設置一個很長的過期頭 ;變化不頻繁而又可能會變的資源可以使用 Last-Modifed來做請求驗證。盡可能的讓資源能夠在緩存中待得更久。關于 HTTP緩存的具體設置和原理此處就不再詳述了,有興趣的可以參考下列文章:
(3)資源合并與壓縮
如果可以的話,盡可能的將外部的腳本、樣式進行合并,多個合為一個。另外, CSS、 Javascript、Image 都可以用相應的工具進行壓縮,壓縮后往往能省下不少空間。
(4)CSS Sprites
合并 CSS圖片,減少請求數的又一個好辦法。
(5)內聯圖像
使用 data: URL scheme的方式將圖片嵌入到頁面或 CSS中,如果不考慮資源管理上的問題的話,不失為一個好辦法。如果是嵌入頁面的話換來的是增大了頁面的體積,而且無法利用瀏覽器緩存。使用在 CSS中的圖片則更為理想一些。
(6)Lazy Load Images
(6). Lazy Load Images(自己對這一塊的內容還是不了解) 這條策略實際上并不一定能減少 HTTP請求數,但是卻能在某些條件下或者頁面剛加載時減少 HTTP請求數。對于圖片而言,在頁面剛加載的時候可以只加載第一屏,當用戶繼續往后滾屏的時候才加載后續的圖片。這樣一來,假如用戶只對第一屏的內容感興趣時,那剩余的圖片請求就都節省了。
2.2 將外部腳本置底(將腳本內容在頁面信息內容加載后再加載)
瀏覽器是可以并發請求的,這一特點使得其能夠更快的加載資源,然而外鏈腳本在加載時卻會阻塞其他資源,例如在腳本加載完成之前,它后面的圖片、樣式以及其他腳本都處于阻塞狀態,直到腳本加載完成后才會開始加載。如果將腳本放在比較靠前的位置,則會影響整個頁面的加載速度從而影響用戶體驗
2.3 異步執行inline腳本
inline inline腳本對性能的影響與外部腳本相比,是有過之而無不及。首頁,與外部腳本一樣,inline腳本在執行的時候一樣會阻塞并發請求,除此之外,由于瀏覽器在頁面處理方面是單線程的,當inline腳本在頁面的渲染之前執行時,頁面的渲染工作會會被推遲。簡而言之,inline腳本在執行的時候,頁面處于空白狀態。鑒于以上兩點原因,建議將執行時間較長的inline腳本異步執行,異步的方式有很多種,例如使用腳本元素的defer屬性(存在兼容性問題和其他一些問題,例如不能使用document.write),使用setTimeout,此外,在HTML5中引入了 Web Workers 的機制,恰恰可以解決此類問題。
4.懶惰加載JavaScript
隨著的Javascript框架的流行,越來越多的站點也使用起了框架。不過,一個框架往往包括了很多的功能實現,這些功能并不是每一個頁面都需要的,如果下載了不需要的腳本則算得上是一種資源浪費 - 既浪費了帶寬又浪費了執行花費的時間。目前的做法大概有兩種,一種是為那些流量特別大的頁面專門定制一個專用的迷你版框架,另一種則是Lazy Load
1.5 將 CSS放在 HEAD中
如果將 CSS放在其他地方比如 BODY中,則瀏覽器有可能還未下載和解析到 CSS就已經開始渲染頁面了,這就導致頁面由無 CSS狀態跳轉到 CSS狀態,用戶體驗比較糟糕。除此之外,有些瀏覽器會在 CSS下載完成后才開始渲染頁面,如果 CSS放在靠下的位置則會導致瀏覽器將渲染時間推遲。
減少不必要的 HTTP跳轉
對于以下目錄形式訪問的HTTP鏈接,很多人都會忽略鏈接最后是否帶'/',假如你的服務器對此是區別對待的話,那么你也需要注意,這其中很很可以隱藏了301跳轉,增加了多余請求。具體參見下圖,其中第一個鏈接是以'/'結尾的方式訪問的,于是服務器有了一次跳轉。
8. 避免重復的資源請求
這種情況主要是由于疏忽或頁面由多個模塊拼接而成,然后每個模塊中請求了同樣的資源時,會導致資源的重復請求
二,代碼級優化
1. Javascript
(1). DOM
DOM操作應該是腳本中最耗性能的一類操作,例如增加、修改、刪除 DOM元素或者對 DOM集合進行操作。如果腳本中包含了大量的 DOM操作則需要注意以下幾點:
a. HTML Collection(HTML收集器,返回的是一個數組內容信息)
在腳本中 document.images、document.forms 、getElementsByTagName()返回的都是 HTMLCollection類型的集合,在平時使用的時候大多將它作為數組來使用,因為它有 length屬性,也可以使用索引訪問每一個元素。不過在訪問性能上則比數組要差很多,原因是這個集合并不是一個靜態的結果,它表示的僅僅是一個特定的查詢,每次訪問該集合時都會重新執行這個查詢從而更新查詢結果。所謂的 “訪問集合” 包括讀取集合的 length屬性、訪問集合中的元素。
因此,當你需要遍歷 HTML Collection的時候,盡量將它轉為數組后再訪問,以提高性能。即使不轉換為數組,也請盡可能少的訪問它,例如在遍歷的時候可以將 length屬性、成員保存到局部變量后再使用局部變量。
b. Reflow & Repaint
除了上面一點之外, DOM操作還需要考慮瀏覽器的 Reflow和Repaint ,因為這些都是需要消耗資源的,具體的可以參加以下文章:
(2). 慎用 with
with(obj){ p = 1}; 代碼塊的行為實際上是修改了代碼塊中的 執行環境 ,將obj放在了其作用域鏈的最前端,在 with代碼塊中訪問非局部變量是都是先從 obj上開始查找,如果沒有再依次按作用域鏈向上查找,因此使用 with相當于增加了作用域鏈長度。而每次查找作用域鏈都是要消耗時間的,過長的作用域鏈會導致查找性能下降。
因此,除非你能肯定在 with代碼中只訪問 obj中的屬性,否則慎用 with,替代的可以使用局部變量緩存需要訪問的屬性。
(3). 避免使用 eval和 Function
每次 eval 或 Function 構造函數作用于字符串表示的源代碼時,腳本引擎都需要將源代碼轉換成可執行代碼。這是很消耗資源的操作 —— 通常比簡單的函數調用慢 100倍以上。
eval 函數效率特別低,由于事先無法知曉傳給 eval 的字符串中的內容,eval在其上下文中解釋要處理的代碼,也就是說編譯器無法優化上下文,因此只能有瀏覽器在運行時解釋代碼。這對性能影響很大。
Function 構造函數比 eval略好,因為使用此代碼不會影響周圍代碼 ;但其速度仍很慢。
此外,使用 eval和 Function也不利于Javascript 壓縮工具執行壓縮。
(4). 減少作用域鏈查找(這方面設計到一些內容的相關問題)
前文談到了作用域鏈查找問題,這一點在循環中是尤其需要注意的問題。如果在循環中需要訪問非本作用域下的變量時請在遍歷之前用局部變量緩存該變量,并在遍歷結束后再重寫那個變量,這一點對全局變量尤其重要,因為全局變量處于作用域鏈的最頂端,訪問時的查找次數是最多的。
低效率的寫法:
// 全局變量
var globalVar = 1;
function myCallback(info){
for( var i = 100000; i--;){
//每次訪問 globalVar 都需要查找到作用域鏈最頂端,本例中需要訪問 100000 次
globalVar += i;
}
}
更高效的寫法:
// 全局變量
var globalVar = 1;
function myCallback(info){
//局部變量緩存全局變量
var localVar = globalVar;
for( var i = 100000; i--;){
//訪問局部變量是最快的
localVar += i;
}
//本例中只需要訪問 2次全局變量
在函數中只需要將 globalVar中內容的值賦給localVar 中區
globalVar = localVar;
}
此外,要減少作用域鏈查找還應該減少閉包的使用。
(5). 數據訪問
Javascript中的數據訪問包括直接量 (字符串、正則表達式 )、變量、對象屬性以及數組,其中對直接量和局部變量的訪問是最快的,對對象屬性以及數組的訪問需要更大的開銷。當出現以下情況時,建議將數據放入局部變量:
a. 對任何對象屬性的訪問超過 1次
b. 對任何數組成員的訪問次數超過 1次
另外,還應當盡可能的減少對對象以及數組深度查找。
(6). 字符串拼接
在 Javascript中使用"+" 號來拼接字符串效率是比較低的,因為每次運行都會開辟新的內存并生成新的字符串變量,然后將拼接結果賦值給新變量。與之相比更為高效的做法是使用數組的 join方法,即將需要拼接的字符串放在數組中最后調用其 join方法得到結果。不過由于使用數組也有一定的開銷,因此當需要拼接的字符串較多的時候可以考慮用此方法。
2.2 CSS選擇符
在大多數人的觀念中,都覺得瀏覽器對 CSS選擇符的解析式從左往右進行的,例如
#toc A { color: #444; }
這樣一個選擇符,如果是從右往左解析則效率會很高,因為第一個 ID選擇基本上就把查找的范圍限定了,但實際上瀏覽器對選擇符的解析是從右往左進行的。如上面的選擇符,瀏覽器必須遍歷查找每一個 A標簽的祖先節點,效率并不像之前想象的那樣高。根據瀏覽器的這一行為特點,在寫選擇符的時候需要注意很多事項。
2.3 HTML
對 HTML本身的優化現如今也越來越多的受人關注了 。
2.4 Image壓縮
圖片壓縮是個技術活,不過現如今這方面的工具也非常多,壓縮之后往往能帶來不錯的效果,具體的壓縮原理以及方法在《 Even Faster Web Sites》第10 章有很詳細的介紹,有興趣的可以去看看。
三、常見問題
如何進行http緩存?
四、解決方案
1、設置<meta http-equiv="Cache-Control" content="max-age=7200">
2、設置<meta http-equiv="expires" content="GMT格式時間">
五、編碼實戰
無
六、拓展思考
無
七、參考文獻
參考一: Web前端應該從哪些方面來優化網站?
參考二: HTML優化
八、更多討論
Q : 鏈接后面是否帶“/”有什么區別?
A : 鏈接后有“/”表示請求的是文件路徑,否則請求的是文件;
Q : HTML Collection都有哪些?
A : 下面的每個項目(以及它們指定的屬性)都返回 HTMLCollection:
Document (images, applets, links, forms, anchors)
form (elements)
map (areas)
select (options)
table (rows, tBodies)
tableSection (rows)
row (cells)
Q :css選擇符性能優先級順序是什么?
A : 1.id選擇器(#myid),最優
2.類選擇器(.myclassname)
3.標簽選擇器(div,h1,p)
4.相鄰選擇器(h1+p)
5.子選擇器(ul < li)
6.后代選擇器(li a)
7.通配符選擇器(*)
8.屬性選擇器(a[rel="external"])
9.偽類選擇器(a:hover,li:nth-child)
本文來源于網絡,若有侵權請聯系3449817223#qq.com,將在第一時間刪除。