前端性能優化 Web前端應該從哪些方面來優化網站?

作者:斯迪
鏈接:https://www.zhihu.com/question/21658448/answer/18903129
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

前端是龐大的,包括 HTML、 CSS、 Javascript、Image 、Flash等等各種各樣的資源。前端優化是復雜的,針對方方面面的資源都有不同的方式。那么,前端優化的目的是什么 ?
  1. 從用戶角度而言,優化能夠讓頁面加載得更快、對用戶的操作響應得更及時,能夠給用戶提供更為友好的體驗。
  2. 從服務商角度而言,優化能夠減少頁面請求數、或者減小請求所占帶寬,能夠節省可觀的資源。
  總之,恰當的優化不僅能夠改善站點的用戶體驗并且能夠節省相當的資源利用。
  前端優化的途徑有很多,按粒度大致可以分為兩類,第一類是頁面級別的優化,例如 HTTP請求數、腳本的無阻塞加載、內聯腳本的位置優化等 ;第二類則是代碼級別的優化,例如 Javascript中的DOM 操作優化、CSS選擇符優化、圖片優化以及 HTML結構優化等等。另外,本著提高投入產出比的目的,后文提到的各種優化策略大致按照投入產出比從大到小的順序排列。
  一、頁面級優化
  1. 減少 HTTP請求數
  這條策略基本上所有前端人都知道,而且也是最重要最有效的。都說要減少 HTTP請求,那請求多了到底會怎么樣呢 ?首先,每個請求都是有成本的,既包含時間成本也包含資源成本。一個完整的請求都需要經過 DNS尋址、與服務器建立連接、發送數據、等待服務器響應、接收數據這樣一個 “漫長” 而復雜的過程。時間成本就是用戶需要看到或者 “感受” 到這個資源是必須要等待這個過程結束的,資源上由于每個請求都需要攜帶數據,因此每個請求都需要占用帶寬。另外,由于瀏覽器進行并發請求的請求數是有上限的 (具體參見此處 ),因此請求數多了以后,瀏覽器需要分批進行請求,因此會增加用戶的等待時間,會給用戶造成站點速度慢這樣一個印象,即使可能用戶能看到的第一屏的資源都已經請求完了,但是瀏覽器的進度條會一直存在。
  減少 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緩存的具體設置和原理此處就不再詳述了,有興趣的可以參考下列文章:
HTTP1.1協議中關于緩存策略的描述
Fiddler HTTP Performance中關于緩存的介紹
  (3). 資源合并與壓縮
  如果可以的話,盡可能的將外部的腳本、樣式進行合并,多個合為一個。另外, CSS、 Javascript、Image 都可以用相應的工具進行壓縮,壓縮后往往能省下不少空間。
  (4). CSS Sprites
  合并 CSS圖片,減少請求數的又一個好辦法。
  (5). Inline Images
  使用 data: URL scheme的方式將圖片嵌入到頁面或 CSS中,如果不考慮資源管理上的問題的話,不失為一個好辦法。如果是嵌入頁面的話換來的是增大了頁面的體積,而且無法利用瀏覽器緩存。使用在 CSS中的圖片則更為理想一些。
  (6). Lazy Load Images(自己對這一塊的內容還是不了解)
  這條策略實際上并不一定能減少 HTTP請求數,但是卻能在某些條件下或者頁面剛加載時減少 HTTP請求數。對于圖片而言,在頁面剛加載的時候可以只加載第一屏,當用戶繼續往后滾屏的時候才加載后續的圖片。這樣一來,假如用戶只對第一屏的內容感興趣時,那剩余的圖片請求就都節省了。 有啊首頁 曾經的做法是在加載的時候把第一屏之后的圖片地址緩存在 Textarea標簽中,待用戶往下滾屏的時候才 “惰性” 加載。

  2. 將外部腳本置底(將腳本內容在頁面信息內容加載后再加載)
  前文有談到,瀏覽器是可以并發請求的,這一特點使得其能夠更快的加載資源,然而外鏈腳本在加載時卻會阻塞其他資源,例如在腳本加載完成之前,它后面的圖片、樣式以及其他腳本都處于阻塞狀態,直到腳本加載完成后才會開始加載。如果將腳本放在比較靠前的位置,則會影響整個頁面的加載速度從而影響用戶體驗。解決這一問題的方法有很多,在 這里有比較詳細的介紹 (這里是譯文和 更詳細的例子 ),而最簡單可依賴的方法就是將腳本盡可能的往后挪,減少對并發下載的影響。
  3. 異步執行 inline腳本(其實原理和上面是一樣,保證腳本在頁面內容后面加載。)
  inline腳本對性能的影響與外部腳本相比,是有過之而無不及。首頁,與外部腳本一樣, inline腳本在執行的時候一樣會阻塞并發請求,除此之外,由于瀏覽器在頁面處理方面是單線程的,當 inline腳本在頁面渲染之前執行時,頁面的渲染工作則會被推遲。簡而言之, inline腳本在執行的時候,頁面處于空白狀態。鑒于以上兩點原因,建議將執行時間較長的 inline腳本異步執行,異步的方式有很多種,例如使用 script元素的defer 屬性(存在兼容性問題和其他一些問題,例如不能使用 document.write)、使用setTimeout ,此外,在HTML5中引入了 Web Workers的機制,恰恰可以解決此類問題。

  4. Lazy Load Javascript(只有在需要加載的時候加載,在一般情況下并不加載信息內容。)
  隨著 Javascript框架的流行,越來越多的站點也使用起了框架。不過,一個框架往往包括了很多的功能實現,這些功能并不是每一個頁面都需要的,如果下載了不需要的腳本則算得上是一種資源浪費 -既浪費了帶寬又浪費了執行花費的時間。目前的做法大概有兩種,一種是為那些流量特別大的頁面專門定制一個專用的 mini版框架,另一種則是 Lazy Load。YUI 則使用了第二種方式,在 YUI的實現中,最初只加載核心模塊,其他模塊可以等到需要使用的時候才加載。

  5. 將 CSS放在 HEAD中
  如果將 CSS放在其他地方比如 BODY中,則瀏覽器有可能還未下載和解析到 CSS就已經開始渲染頁面了,這就導致頁面由無 CSS狀態跳轉到 CSS狀態,用戶體驗比較糟糕。除此之外,有些瀏覽器會在 CSS下載完成后才開始渲染頁面,如果 CSS放在靠下的位置則會導致瀏覽器將渲染時間推遲。
  6. 異步請求 Callback(就是將一些行為樣式提取出來,慢慢的加載信息的內容)
  在某些頁面中可能存在這樣一種需求,需要使用 script標簽來異步的請求數據。類似:
  Javascript:
/*Callback 函數*/
function myCallback(info){
//do something here
}
  HTML:

  cb返回的內容 :
myCallback('Hello world!');
像以上這種方式直接在頁面上寫 <script>對頁面的性能也是有影響的,即增加了頁面首次加載的負擔,推遲了 DOMLoaded和window.onload 事件的觸發時機。如果時效性允許的話,可以考慮在 DOMLoaded事件觸發的時候加載,或者使用 setTimeout方式來靈活的控制加載的時機。
  7. 減少不必要的 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 ,因為這些都是需要消耗資源的,具體的可以參加以下文章:
如何減少瀏覽器的repaint和reflow?
Understanding Internet Explorer Rendering Behaviour
Notes on HTML Reflow

  (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方法得到結果。不過由于使用數組也有一定的開銷,因此當需要拼接的字符串較多的時候可以考慮用此方法。

  關于 Javascript優化的更詳細介紹請參考:
Write Efficient Javascript(PPT)
Efficient JavaScript
  2. CSS選擇符
  在大多數人的觀念中,都覺得瀏覽器對 CSS選擇符的解析式從左往右進行的,例如
#toc A { color: #444; }
  這樣一個選擇符,如果是從右往左解析則效率會很高,因為第一個 ID選擇基本上就把查找的范圍限定了,但實際上瀏覽器對選擇符的解析是從右往左進行的。如上面的選擇符,瀏覽器必須遍歷查找每一個 A標簽的祖先節點,效率并不像之前想象的那樣高。根據瀏覽器的這一行為特點,在寫選擇符的時候需要注意很多事項,有人已經一一列舉了, 詳情參考此處。

  3. HTML
  對 HTML本身的優化現如今也越來越多的受人關注了,詳情可以參見這篇 總結性文章 。

  4. Image壓縮
  圖片壓縮是個技術活,不過現如今這方面的工具也非常多,壓縮之后往往能帶來不錯的效果,具體的壓縮原理以及方法在《 Even Faster Web Sites》第10 章有很詳細的介紹,有興趣的可以去看看。
  總結
  本文從頁面級以及代碼級兩個粒度對前端優化的各種方式做了一個總結,這些方法基本上都是前端開發人員在開發的過程中可以借鑒和實踐的,除此之外,完整的前端優化還應該包括很多其他的途徑,例如 CDN、 Gzip、多域名、無 Cookie服務器等等,由于對于開發人員的可操作性并不強大,在此也就不多敘述了,詳細的可以參考 Yahoo和Google 的這些“金科玉律?

轉載于:https://www.cnblogs.com/changningios/p/6472237.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253298.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253298.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253298.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

嵌入式NVR發展淺析

隨著視頻監控的高速發展&#xff0c;視頻監控對硬盤錄像機的要求也在不斷提高&#xff0c;在以往“看得見”的基礎上&#xff0c;要求視頻畫面看的更為清晰、準確。相對于傳統硬盤錄像機&#xff0c;NVR最主要的特征就是“網絡化”、“高清化”&#xff0c;在視頻監控“高清化”…

Maven and Nexus2

2019獨角獸企業重金招聘Python工程師標準>>> Maven and Nexus2 Maven是什么&#xff1f; 構建工具&#xff1a; 通過簡單的命令&#xff0c;能夠完成清理、編譯、測試、打包、部署等一系列過程。同時&#xff0c;不得不提的是&#xff0c;Maven是跨平臺的&#xff0…

Linux kernel的中斷子系統之(九):tasklet

返回目錄&#xff1a;《ARM-Linux中斷系統》。 總結&#xff1a; 二介紹了tasklet存在的意義。 三介紹了通過tasklet_struct來抽想一個tasklet&#xff0c;每個CPU維護一個tasklet鏈表tasklet_vec/tasklet_hi_vec&#xff0c;然后介紹了如何定一個一個tasklet(靜態/動態)&#…

市面主要遠場語音交互技術架構

為什么Google Home要采用雙麥方案&#xff0c;而且大部分智能音箱才用環形六麥&#xff1f;事實上&#xff0c;這是由各家不同的技術架構決定的&#xff0c;當前市面上主要存在三種遠場語音交互技術架構。 1、以Google為代表的純云端技術架構 首先就是以Google為代表的純云端技…

iOSPush自動隱藏tabbar

只需要在UITabBarController添加控制器的時候調用YZNav初始化&#xff0c;就可以實現tabbar的自動隱藏了。 直接上github地址&#xff1a;https://github.com/YouZhiZheShiJingCheng/YZNav 轉載于:https://www.cnblogs.com/BK-12345/p/6472815.html

中國智能高清視頻監控未來發展趨勢

瀏覽數: 1228 海康威視&#xff1a;田振華 《中國公共安全》&#xff1a;您認為高清攝像機將朝著哪個方向發展&#xff1f;像素會達到什么標準&#xff1f; 高清攝像機發展趨勢&#xff1a; 一&#xff1a;高清 雖然說現在已經實現高清&#xff0c;但是從顯示效果來看現有的高…

智能音箱 之 功放介紹

基本分類 功率放大器分甲類功放&#xff08;A 類&#xff09;&#xff0c;乙類&#xff08;B 類&#xff09;&#xff0c;甲乙類&#xff08;AB 類&#xff09;和丁類&#xff08;D 類&#xff09;&#xff1b; A 類 指在信號的整個周期內&#xff0c;放大器的任何功率輸出…

create_workqueue和create_singlethread_workqueue【轉】

本文轉載自&#xff1a;http://bgutech.blog.163.com/blog/static/18261124320116181119889/ 1. 什么是workqueueLinux中的Workqueue機制就是為了簡化內核線程的創建。通過調用workqueue的接口就能創建內核線程。并且可以根據當前系統CPU的個數創建線程的數量&#xff0c;使得線…

平安城市與智慧城市對接的關鍵要素

平安城市經過前兩個階段&#xff08;布點、聯網&#xff09;的大規模建設之后&#xff0c;如今正向系統應用深化&#xff0c;數據深入挖掘利用的方向發展。以視頻監控為基礎單元&#xff0c;一些城市開始嘗試在既有的社會治安管理平臺系統基礎上拓展更多的應用功能&#xff0c;…

vue學習之路.02

2019獨角獸企業重金招聘Python工程師標準>>> 第一個vue項目 1.創建 vue init webpack app01 2.安裝依賴 cd app01 npm install 3.構建 npm run dev 啟動本機的8080端口 或 …

等價表達式

小目標的最后一步。 原題鏈接&#xff1a;https://www.luogu.org/problem/show?pid1054 精力不足&#xff0c;代碼工作可能要放在后幾天。。。 思路已經明確了&#xff0c;我說一下。 這道題的大意是給出若干表達式&#xff0c;問這些表達式的值和初始表達式的值是不是相等。 …

解析電子墨水屏技術(工作原理與LCD的區別)

閱讀電子書早已成為大家生活中一部分&#xff0c;方便輕巧的電子版書籍更便于攜帶&#xff0c;而電子閱讀器也不僅僅局限于電腦、手機等傳統設備&#xff0c;新興的電子書閱讀器漸漸為我們所接受。E-ink電子墨水技術就是現在最著名的產品之一&#xff0c;他的出現讓電子書閱讀器…

27:級數求和

27:級數求和 查看提交統計提問總時間限制: 1000ms內存限制: 65536kB描述已知&#xff1a;Sn 1&#xff0b;1&#xff0f;2&#xff0b;1&#xff0f;3&#xff0b;…&#xff0b;1&#xff0f;n。顯然對于任意一個整數K&#xff0c;當n足夠大的時候&#xff0c;Sn大于K。 現給出…

入門視頻采集與處理(BT656簡介) 轉

凡是做模擬信號采集的&#xff0c;很少不涉及BT.656標準的&#xff0c;因為常見的模擬視頻信號采集芯片都支持輸出BT.656的數字信號&#xff0c;那么&#xff0c;BT.656到底是何種格式呢&#xff1f;本文將主要介紹 標準的 8bit BT656&#xff08;4:2:2&#xff09;YCbCr SDTV&…

眼圖(Eye Diagram)與數字信號測試

問題: 什么是眼圖&#xff1f;它用在什么場合&#xff1f;反映了波形的什么信息&#xff1f;NI相應的解決方案是怎樣的&#xff1f; 解答: 眼圖&#xff08;Eye Diagram&#xff09;可以顯示出數字信號的傳輸質量&#xff0c;經常用于需要對電子設備、芯片中串行數字信號或者…

BZOJ 1609 [Usaco2008 Feb]Eating Together麻煩的聚餐:LIS LDS (nlogn)

題目鏈接&#xff1a;http://www.lydsy.com/JudgeOnline/problem.php?id1609 題意&#xff1a; 給你一個只由數字"1,2,3"組成的序列a[i]&#xff0c;共n個數。 你可以任意更改這些數字&#xff0c;使得序列中每一種數字都“站在一起”&#xff0c;并且單調不減或不增…

Oracle 數據庫字典 sys.obj$ 表中關于type#的解釋

sys.obj$ 表是oracle 數據庫字典表中的對象基礎表&#xff0c;所有對象都在該表中有記錄&#xff0c;其中type#字段表明對象類型&#xff0c;比如有一個表 test &#xff0c;則該對象在sys.obj$ 中存在一條記錄&#xff0c;name列為test&#xff0c; type#列為2&#xff0c;表示…

Python高級特性:列表生成式

列表生成式即List Comprehensions&#xff0c;是Python內置的非常簡單卻強大的可以用來創建list的生成式。 最常見的例子&#xff1a; 生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11))&#xff1a;>>> list(range(1, 11)) [1, 2, 3, 4, 5, 6, 7, 8…

2018年智能音箱對比

眾所周知&#xff0c;2014年底&#xff0c;電商巨頭亞馬遜推出智能音箱產品Echo之后&#xff0c;引起市場的強烈反響。隨后、谷歌、微軟、蘋果均開始布局智能音箱市場&#xff0c;國內公司以玲瓏科技打頭陣。2017年國內公司紛紛發布智能音箱&#xff0c;被稱為智能音箱元年。經…