前端性能的优化
主要考慮客戶端性能、服務器端和網絡性能,內容框架來自Yahoo Developer Network(雅虎開發者網站),包含 7 個類別共 35 條前端性能優化最佳實踐,在此基礎上補充了一些相關或者更符合主流技術的內容。
?
前端性能的一個重要指標是頁面加載時間,不僅事關用戶體驗,也是搜索引擎排名考慮的一個因素。
- 來自Google的數據表明,一個有10條數據0.4秒能加載完的頁面,變成30條數據0.9秒加載完之后,流量和廣告收入下降90%。
- Google Map 首頁文件大小從100KB減小到70-80KB后,流量在第一周漲了10%,接下來的三周漲了25%。
- 亞馬遜的數據表明:加載時間增加100毫秒,銷量就下降1%。
以上數據更說明「加載時間就是金錢」,前端優化主要圍繞提高加載速度進行。
一、頁面內容
1. 減少HTTP請求數 Web 前端 80% 的響應時間花在圖片、樣式、腳本等資源下載上。最直接的方式是減少頁面所需資源,但并不現實。所以,減少HTTP請求數主要的途徑是:
- 合并JS/CSS文件。服務器端(CDN)自動合并,基于Node.js的文件合并工具,通過把所有腳本放在一個文件中的方式來減少請求數。
- 使用CSS Sprite將背景圖片合并成一個文件,通過background-image 和background-position 控制顯示
- 行內圖片(Base64編碼)。使用Data URI scheme將圖片嵌入HTML或者CSS中;或者將CSS、JS、圖片直接嵌入HTML中,會增加文件大小,也可能產生瀏覽器兼容及其他性能問題。
減少頁面的HTTP請求數是個起點,這是提升站點首次訪問速度的重要指導原則。
2. 減少DNS查詢 用戶輸入URL以后,瀏覽器首先要查詢域名(hostname)對應服務器的IP地址,一般需要耗費20-120毫秒時間。DNS查詢完成之前,瀏覽器無法從服務器下載任何數據。
基于性能考慮,ISP、局域網、操作系統、瀏覽器都會有相應的DNS緩存機制。
- IE緩存30分鐘,可以通過注冊表中DnsCacheTimeout項設置;
- Firefox緩存1分鐘,通過network.dnsCacheExpiration配置;
另外減少不同的主機名可減少DNS查找,減少不同主機名的數量同時也減少了頁面能夠并行下載的組件數量,避免DNS查找削減了響應時間,而減少并行下載數量卻增加了響應時間。原則是把組件分散在2到4個主機名下,這是同時減少DNS查找和允許高并發下載的折中方案。
3. 避免重定向 HTTP重定向通過301/302狀態碼實現。下面是一個有301狀態碼的HTTP頭
HTTP/1.1 301 Moved Permanently Location: http://example.com/newuri Content-Type: text/html瀏覽器會自動跳轉到Location域指明的URL。重定向需要的所有信息都在HTTP頭部,而響應體一般是空的。其實額外的HTTP頭,比如Expires和Cache-Control也表示重定向。除此之外還有別的跳轉方式:refresh元標簽和JavaScript,但如果你必須得做重定向,最好用標準的3xxHTTP狀態碼,主要是為了讓返回按鈕能正常使用。
客戶端收到服務器的重定向響應后,會根據響應頭中Location的地址再次發送請求。重定向會影響用戶體驗,尤其是多次重定向時,用戶在一段時間內看不到任何內容,只看到瀏覽器進度條一直在刷新。
- 最浪費的重定向經常發生、而且很容易被忽略:URL 末尾應該添加/但未添加。比如,訪問http://astrology.yahoo.com/astrology將被301重定向到http://astrology.yahoo.com/astrology/(注意末尾的 /)。如果使用 Apache,可以通過Alias或mod_rewrite或DirectorySlash解決這個問題。
- 網站域名變更:CNAME結合Alias或mod_rewrite或者其他服務器類似功能實現跳轉。
4. 緩存Ajax請求 最重要的的優化方式是緩存響應結果。有尚未過期的Expires或者Cache-Control HTTP頭,那么之前的資源就可以從緩存中讀出。必須通知瀏覽器,應該繼續使用之前緩存的資源響應,還是去請求一個新的。可以通過給資源的Ajax URL里添加一個表明用戶資源最后修改時間的時間戳來實現。如果資源從上一次下載之后再沒有被修改過,時間戳不變,資源就將從瀏覽器緩存中直接讀出,從而避免一次額外的HTTP往返消耗。詳見服務器-添加Expires或Cache響應頭。
5. 延遲加載 頁面初始加載時哪些內容是絕對必需的?不在答案之列的資源都可以延遲加載。比如:
- 非首屏使用的數據、樣式、腳本、圖片等;
- 用戶交互時才會顯示的內容。
遵循「漸進增強」理念開發的網站:JavaScript用于增強用用戶體驗,但沒有(不支持) JavaScript也能正常工作,完全可以延遲加載JavaScript。
將首屏以外的HTML放在不渲染的元素中,如隱藏的<textarea>,或者type屬性為非執行腳本的<script>標簽中,減少初始渲染的DOM元素數量,提高速度。等首屏加載完成或者用戶操作時,再去渲染剩余的頁面內容。
6. 預加載 預先加載利用瀏覽器空閑時間請求將來要使用的資源,以便用戶訪問下一頁面時更快地響應。
- 無條件預先加載:頁面加載完成(load)后,馬上獲取其他資源。以 google.com 為例,首頁加載完成后會立即下載一個 Sprite 圖片,此圖首頁不需要,但是搜索結果頁要用到。
- 有條件預先加載:根據用戶行為預判用戶去向,預載相關資源。比如search.yahoo.com開始輸入時會有額外的資源加載。Chrome 等瀏覽器的地址欄也有類似的機制。
- 有「陰謀」的預先加載:頁面即將上線新版前預先加載新版內容。網站改版后由于緩存、使用習慣等原因,會有舊版的網站更快更流暢的反饋。為緩解這一問題,在新版上線之前,舊版可以利用空閑提前加載一些新版的資源緩存到客戶端,以便新版正式上線后更快的載入。
7. 減少DOM元素數量 復雜的頁面不僅下載的字節更多,JavaScript DOM操作也更慢。例如,同是添加一個事件處理器,500個元素和5000個元素的頁面速度上會有很大區別。
從以下幾個角度考慮移除不必要的標記:
- 是否還在使用表格布局?
- 塞進去更多的<div>僅為了處理布局問題?也許有更好、更語義化的標記。
- 能通過偽元素實現的功能,就沒必要添加額外元素,如清除浮動。
瀏覽器控制臺中輸入以下代碼可以計算出頁面中有多少 DOM 元素:
document.getElementsByTagName('*').length
為什么不使用表格布局?
- 更多的標簽,增加文件大小;
- 不易維護,無法適應響應式設計;
- 性能考量,默認的表格布局算法會產生大量重繪
8. 劃分內容到不同域名 瀏覽器一般會限制每個域的并行線程(一般為6個,甚至更少),使用不同的域名可以最大化下載線程,但注意保持在2-4個域名內,以避免DNS查詢損耗。
例如,動態內容放在csspod.com上,靜態資源放在static.csspod.com上。這樣還可以禁用靜態資源域下的Cookie,減少數據傳輸,詳見Cookie 優化。
9. 盡量減少iframe的使用 用iframe可以把一個HTML文檔插入到父文檔里,重要的是明白iframe是如何工作的并高效地使用它。
<iframe>的優點:
- 可以用來加載速度較慢的第三方資源,如廣告、徽章;
- 可用作安全沙箱;
- 可以并行下載腳本。
<iframe>的缺點:
- 加載代價昂貴,即使是空的頁面;
- 阻塞頁面 load 事件觸發;
Iframe 完全加載以后,父頁面才會觸發 load 事件。 Safari、Chrome 中通過 JavaScript 動態設置 iframe src 可以避免這個問題。
- 缺乏語義。
10. 避免404錯誤 HTTP請求很昂貴,返回無效的響應(如404未找到)完全沒必要,降低用戶體驗而且毫無益處。 一些網站設計很酷炫、有提示信息的404頁面,有助于提高用戶體驗,但還是浪費服務器資源。尤其糟糕的是外部腳本返回404,不僅阻塞其他資源下載,瀏覽器還會嘗試把404頁面內容當作JavaScript解析,消耗更多資源。
?
二、服務器
1. 使用CDN 用戶與服務器的物理距離對響應時間也有影響。把內容部署在多個地理位置分散的服務器上能讓用戶更快地載入頁面。但具體要怎么做呢?
網站80-90%響應時間消耗在資源下載上,減少資源下載時間是性能優化的黃金法則。相比分布式架構的復雜和巨大投入,靜態內容分發網絡(CDN)可以以較低的投入,獲得加載速度有效提升。
內容分發網絡(CDN)是一組分散在不同地理位置的web服務器,用來給用戶更高效地發送內容。典型地,選擇用來發送內容的服務器是基于網絡距離的衡量標準的。例如:選跳數(hop)最少的或者響應時間最快的服務器。
2. 添加Expires或Cache-Control響應頭
- 靜態內容:將 Expires 響應頭設置為將來很遠的時間,實現「永不過期」策略;
- 動態內容:設置合適的 Cache-Control 響應頭,讓瀏覽器有條件地發起請求。
Cache-Control頭在HTTP/1.1規范中定義,取代了之前用來定義響應緩存策略的頭(例如 Expires、Pragma)。當前的所有瀏覽器都支持Cache-Control,因此,使用它就夠了。
3. 啟用Gzip 前端工程師可以想辦法明顯地縮短通過網絡傳輸HTTP請求和響應的時間。毫無疑問,終端用戶的帶寬速度,網絡服務商,對等交換點的距離等等,都是開發團隊所無法控制的。但還有別的能夠影響響應時間的因素,壓縮可以通過減少HTTP響應的大小來縮短響應時間。
Gzip壓縮通常可以減少70%的響應大小,對某些文件更可能高達90%,比Deflate更高效。主流 Web 服務器都有相應模塊,而且絕大多數瀏覽器支持gzip解碼。所以,應該對HTML、CSS、JS、XML、JSON等文本類型的內容啟用壓縮。
注意!!! 圖片和 PDF 文件不要使用 gzip。它們本身已經壓縮過,再使用 gzip 壓縮不僅浪費 CPU 資源,而且還可能增加文件體積。
從HTTP/1.1開始,web客戶端就有了支持壓縮的Accept-Encoding HTTP請求頭。
Accept-Encoding: gzip, deflate
如果web服務器看到這個請求頭,它就會用客戶端列出的一種方式來壓縮響應。web服務器通過Content-Encoding響應頭來通知客戶端。
Content-Encoding: gzip
?
4. 配置 Etag 實體標簽(ETags),是服務器和瀏覽器用來決定瀏覽器緩存中組件與源服務器中的組件是否匹配的一種機制(“實體”也就是組件:圖片,腳本,樣式表等等)。添加ETags可以提供一種實體驗證機制,比最后修改日期更加靈活。一個ETag是一個字符串,作為一個組件某一具體版本的唯一標識符。唯一的格式約束是字符串必須用引號括起來,源服務器用相應頭中的ETag來指定組件的ETag。
HTTP/1.1 200 OKLast-Modified: Tue, 12 Dec 2006 03:03:59 GMT ETag: "10c24bc-4ab-457e1c1f" Content-Length: 12195然后,如果瀏覽器必須驗證一個組件,它用If-None-Match請求頭來把ETag傳回源服務器。如果ETags匹配成功,會返回一個304狀態碼,這樣就減少了12195個字節的響應體。Etag 通過文件版本標識,方便服務器判斷請求的內容是否有更新,如果沒有就響應 304,避免重新下載。
GET /i/yahoo.gif HTTP/1.1 Host: us.yimg.com If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT If-None-Match: "10c24bc-4ab-457e1c1f" HTTP/1.1 304 Not Modified?
5. 盡早輸出(flush)緩沖 用戶請求頁面時,服務器通常需要花費200 ~ 500毫秒來組合 HTML 頁面。在此期間,瀏覽器處于空閑、等待數據狀態。使用PHP中的flush()函數,可以發送部分已經準備好的 HTML到瀏覽器,以便服務器還在忙于處理剩余頁面時,瀏覽器可以提前開始獲取資源。
可以考慮在</head>之后輸出一次緩沖,HTML head一般比較容易生成,先發送以便瀏覽器開始獲取<head>里引用的CSS等資源。
<!-- css, js --> </head> <?php flush(); ?> <body> <!-- content -->6. Ajax請求使用GET方法 瀏覽器執行XMLHttpRequest POST請求時分成兩步,先發送Http Header,再發送data。而GET只使用一個TCP數據包(Http Header與data)發送數據,所以首選GET方法。
根據HTTP規范,GET用于獲取數據,POST則用于向服務器發送數據,所以Ajax請求數據時使用GET更符合規范。
7. 避免圖片src為空 圖片src屬性值為空字符串可能以下面兩種形式出現:
HTML:
<img src="" />JavaScript:
var img = new Image(); img.src = "";雖然src屬性為空字符串,但瀏覽器仍然會向服務器發起一個HTTP請求:
- IE 向頁面所在的目錄發送請求;
- Safari、Chrome、Firefox向頁面本身發送請求;
- Opera不執行任何操作。
空src產生請求的后果不容小覷:
- 給服務器造成意外的流量負擔,尤其時日 PV 較大時;
- 浪費服務器計算資源;
- 可能產生報錯。
空的href屬性也存在類似問題。用戶點擊空鏈接時,瀏覽器也會向服務器發送HTTP請求,可以通過JavaScript阻止空鏈接的默認的行為。
?
三、Cookie
1. 減少 Cookie 大小 Cookie被用于身份認證、個性化設置等諸多用途。Cookie通過HTTP頭在服務器和瀏覽器間來回傳送,減少Cookie大小可以降低其對響應速度的影響。
- 去除不必要的 Cookie;
- 盡量壓縮 Cookie 大小;
- 注意設置 Cookie 的 domain 級別,如無必要,不要影響到 sub-domain;
- 設置合適的過期時間。
2. 靜態資源使用無Cookie域名 靜態資源一般無需使用Cookie,可以把它們放在使用二級域名或者專門域名的無Cookie服務器上,降低Cookie傳送的造成的流量浪費,提高響應速度。
?
四、CSS
1. 把樣式表放在<head>中 把樣式表放在<head>中可以讓頁面漸進渲染,盡早呈現視覺反饋,給用戶加載速度很快的感覺。
這對內容比較多的頁面尤為重要,用戶可以先查看已經下載渲染的內容,而不是盯著白屏等待。
如果把樣式表放在頁面底部,一些瀏覽器為減少重繪,會在 CSS 加載完成以后才渲染頁面,用戶只能對著白屏干瞪眼,用戶體驗極差。把樣式表放到文檔的HEAD部分能讓頁面看起來加載地更快。
2. 不要使用CSS表達式 CSS表達式可以在CSS里執行JavaScript,僅IE5-IE7支持,IE8標準模式已經廢棄。 CSS表達式超出預期的頻繁執行,頁面滾動、鼠標移動時都會不斷執行,帶來很大的性能損耗。
3. 使用<link>替代@import 對于IE某些版本,@import的行為和放在頁面底部一樣。所以,不要用它。
4. 不要使用 filter AlphaImageLoader為IE5.5-IE8專有的技術,和CSS表達式一樣,放進博物館吧。IE專有的AlphaImageLoader濾鏡可以用來修復IE7之前的版本中半透明PNG圖片的問題。在圖片加載過程中,這個濾鏡會阻塞渲染,卡住瀏覽器,還會增加內存消耗而且是被應用到每個元素的,而不是每個圖片,所以會存在一大堆問題。
注意!!!這里所說的不是 CSS3 Filter
?
五、Javasript
1. 把腳本放在頁面底部 瀏覽器下載腳本時,會阻塞其他資源并行下載,即使是來自不同域名的資源。因此,最好將腳本放在底部,以提高頁面加載速度。
一些特殊場景無法將腳本放到頁面底部的,可以考慮<script>的以下屬性:
- defer 屬性;
- HTML5 新增的async屬性。
2. 使用外部JavaScript和CSS 外部JavaScript和CSS文件可以被瀏覽器緩存,在不同頁面間重用,也能降低頁面大小。
當然,實際中也需要考慮代碼的重用程度。如果僅僅是某個頁面使用到的代碼,可以考慮內嵌在頁面中,減少HTTP請求數。另外,可以在首頁加載完成以后,預先加載子頁面的資源。
3. 壓縮JavaScript和CSS 壓縮代碼可以移除非功能性的字符(注釋、空格、空行等),減少文件大小,提高載入速度。
得益于Node.js的流行,開源社區涌現出許多高效、易用的前端優化工具,JavaScript 和CSS壓縮類的,不敢說多如牛毛,多入雞毛倒是一點不夸張,如[UglifyJS 2] (github.com/mishoo/Ugli…)、csso、cssnano 等。
對于內嵌的CSS和JavaScript,也可以通過htmlmin等工具壓縮。
這些項目都有Gulp、Webpack等流行構建工具的配套版本。
4. 移除重復腳本 重復的腳本不僅產生不必要的HTTP請求,而且重復解析執行浪費時間和計算資源。
5. 減少DOM操作 JavaScript 操作 DOM 很慢,尤其是 DOM 節點很多時。
使用時應該注意:
- 緩存已經訪問過的元素;
- 使用DocumentFragment暫存DOM,整理好以后再插入DOM樹;
- 操作className,而不是多次讀寫style;
- 避免使用JavaScript修復布局。
6. 使用高效的事件處理
- 減少綁定事件監聽的節點,如通過事件委托;
- 盡早處理事件,在DOMContentLoaded即可進行,不用等到load以后。
?
六、圖片
1. 優化圖片 嘗試把GIF格式轉換成PNG格式,看看是否節省空間。在所有的PNG圖片上運行pngcrush(或者其它PNG優化工具)。
YDN列出的相關工具缺乏易用性,建議參考以下工具
- imagemin
- imageoptim.com
TODO:
- PNG 終極優化;
- Webp 相關內容;
- SVG 相關內容。
PNG終極優化
- Most Effective Method to Reduce and Optimize PNG Images
- Clever PNG Optimization Techniques
2. 優化CSS Sprite
- 水平排列Sprite中的圖片,垂直排列會增加圖片大小;
- Spirite中把顏色較近的組合在一起可以降低顏色數,理想狀況是低于256色以適用PNG8格式;
- 不要在Spirite的圖像中間留有較大空隙。減少空隙雖然不太影響文件大小,但可以降低用戶代理把圖片解壓為像素圖的內存消耗,對移動設備更友好。
3. 不要在HTML中縮放圖片 不要使用<img>的width、height縮放圖片,如果用到小圖片,就使用相應大小的圖片。如果需要
<img width="100" height="100" src="mycat.jpg" alt="My Cat" />那么圖片本身(mycat.jpg)應該是100x100px的,而不是去縮小500x500px的圖片。
很多 CMS 和 CDN 都提供圖片裁切功能。
補充:設置圖片的寬和高,以免瀏覽器按照「猜」的寬高給圖片保留的區域和實際寬高差異,產生重繪。
4. 使用體積小、可緩存的favicon.ico Favicon.ico一般存放在網站根目錄下,無論是否在頁面中設置,瀏覽器都會嘗試請求這個文件。
所以確保這個圖標:
- 存在(避免 404);
- 盡量小,最好小于 1K;
- 設置較長的過期時間。
對于較新的瀏覽器,可以使用PNG格式的favicon。
?
七、移動端
1. 保證所有組件都小于25K 這個限制是因為iPhone不能緩存大于25K的組件,注意這里指的是未壓縮的大小。這就是為什么縮減內容本身也很重要,因為單純的gzip可能不夠。
2. 打包內容為分段(multipart)文檔 把各個組件打包成一個像有附件的電子郵件一樣的復合文檔里,可以用一個HTTP請求獲取多個組件(記住一點:HTTP請求是代價高昂的)。用這種方式的時候,要先檢查用戶代理是否支持(iPhone就不支持)。
?
總結
寫到這里,雅虎的35條軍規算是介紹完了。條目雖然很多,但經過分類,可以發現,性能優化主要切入點可以從以下幾個方面去考慮:
- 資源本身大小的壓縮優化(想辦法減少資源的體積)
- 網絡請求的全過程(從url地址欄輸入發送請求開始到返回響應包的每個環節)
- 瀏覽器渲染的全過程(拿到資源后瀏覽器渲染的每個環節) 因此,要徹底掌握優化的方法,必須對http請求的全過程以及瀏覽器的渲染全過程都有深入的理解。
?
轉載于:https://www.cnblogs.com/zhuangch/p/11546725.html
總結
- 上一篇: Elasticsearch入门(一)基本
- 下一篇: java 循环里声明变量赋值_在Java