前端性能優化小紀

grayrover 6年前發布 | 36K 次閱讀 性能優化 CSS Web服務器 前端技術

天下武功,無堅不破,唯快不破。對前端而言,快意味著要求資源體量更小、數量更精簡、內容更早呈現、交互更加人性化。當項目做到一定程度,就應該考慮性能的問題,前端的性能優化有諸多有跡可循的理論和方法,比如 Yahoo!性能軍規、Google PageSpeed Insights Rules。

我們團隊一個比較老的項目首屏加載大概需要20多秒,這嚴重影響了用戶體驗,于是進行了一次首屏加載的性能優化。

瀏覽器渲染過程

首先,稍微了解一下,瀏覽器接收到HTML/CSS/JavaScript等資源后的渲染過程:

瀏覽器在收到 HTML 文檔之后會對文檔進行解析開始構建 DOM (Document Object Model) 樹,進而在文檔中發現樣式表,開始解析 CSS 來構建 CSSOM(CSS Object Model)樹,這兩者都構建完成后,開始構建渲染樹。

DOM樹描述了文檔的結構與內容,CSSOM樹則描述了對文檔應用的樣式規則,想要渲染出頁面,就需要將DOM樹與CSSOM樹結合在一起,這就是渲染樹。渲染樹構建完畢后,瀏覽器得到了每個可見節點的內容與其樣式,下一步工作則需要計算每個節點在窗口內的確切位置與大小,也就是布局階段。當Layout布局事件完成后,瀏覽器會立即發出Paint Setup與Paint事件,開始將渲染樹繪制成像素,繪制所需的時間跟CSS樣式的復雜度成正比,繪制完成后,用戶就可以看到頁面的最終呈現效果了。

暫緩JavaScript解析

在上圖構建DOM樹時,<script>標簽可能會阻塞html解析,從而影響首頁加載速度,可以使用async進行異步加載或者用defer進行延遲加載。

async屬性表示腳本會在下載后盡快執行,但不能保證腳本會按照順序執行。

defer屬性表示腳本會先下載,但會在整個頁面都解析完成后再運行,并且按照腳本出現的先后順序執行。

用網上一張圖能比較明顯得看出兩者的不同之處。

藍色線代表網絡讀取,紅色線代表執行時間,這倆都是針對腳本的;綠色線代表 HTML 解析。

用這兩個屬性可以很好解決由<script>引起地加載緩慢問題。

減少不必要的HTML標簽

從瀏覽器渲染的流程可以看出,如果HTML中有很多不必要的標簽會影響DOM解析速度并且增加了HTML文件的大小,可以對嵌套過深的結構進行優化,去除不必要的標簽。

減少CSS嵌套

CSS嵌套過深,會影響瀏覽器查找選擇器的速度,一定程度上產出了很多冗余的字節,一般最多嵌套3層。

啟用CSS Sprite

CSS Sprites在國內很多人叫css精靈,是一種網頁圖片應用處理方式。它允許你將一個頁面涉及到的所有零星圖片都包含到一張大圖中去,這樣一來,當訪問該頁面時,載入的圖片就不會像以前那樣一幅一幅地慢慢顯示出來了。

該項目首頁有有三張svg的圖片,參考SVG Sprite對這三張照片進行了svg sprite的簡單處理,后續在angular/cli中也可以參照這個SVG icon system with angular-cli對項目中的svg圖片進行統一的處理。

進行css sprite處理時,注意以下幾點:

  • 把圖片橫向合并,這樣圖片大小更小
  • 間距不要太大,這對圖片大小影響不是很大,但對客戶端解壓時需要的內存更少

進行css sprite處理后,降低了首頁資源請求次數。

對于圖標類的圖片,最好用iconfont來減少圖片的額外請求。

壓縮靜態資源

合并打包后的js、css、圖片文件體積一般會比較大,這個時候要對它們進行壓縮處理。gulp和webpack都有相應的壓縮插件。

針對個別圖片,有時候也可以單獨拿出來處理,可以去tinypng 進行在線壓縮。

使用lazyload和preloading

在Angular中,可以在路由中用loadChildren來實現lazyload,這樣可以實現按需加載,加快加載速度。

{
      path: 'home',
      loadChildren: 'app/home/home.module#HomeModule',
    },

首頁顯示的模塊不應該過大,我們項目中首頁加載的模塊雖然使用了lazyload,但是模塊太大,以至于嚴重影響了加載速度,于是對模塊進行了切割,分成2個模塊,對于第二個模塊進行了preloading,這樣在首頁加載完畢后,會對該模塊進行預加載,加快了路由切換時的速度。關于preloading可以參考Angular官網的自定義預加載策略。

Nginx啟用Gzip壓縮

HTTP協議上的gzip編碼是一種用來改進web應用程序性能的技術,web服務器和客戶端(瀏覽器)必須共同支持gzip。目前主流的瀏覽器,Chrome,firefox,IE等都支持該協議。常見的服務器如Apache,Nginx,IIS同樣支持gzip。

gzip壓縮比率在3到10倍左右,可以大大節省服務器的網絡帶寬。而在實際應用中,并不是對所有文件進行壓縮,通常只是壓縮靜態文件。

在Nginx中,啟用gzip:

# 開啟gzip
    gzip on;
    # 啟用gzip壓縮的最小文件,小于設置值的文件將不會壓縮
    gzip_min_length 1k;
    # gzip 壓縮級別,1-10,數字越大壓縮的越好,也越占用CPU時間
    gzip_comp_level 5;
    # 進行壓縮的文件類型。javascript有多種形式。其中的值可以在 mime.types 文件中找到。
    gzip_types 
        application/atom+xml
        application/javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rss+xml
        application/vnd.geo+json
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-web-app-manifest+json
        application/xhtml+xml
        application/xml
        font/opentype
        image/bmp
        image/svg+xml
        image/x-icon
        text/cache-manifest
        text/css
        text/plain
        text/vcard
        text/vnd.rim.location.xloc
        text/vtt
        text/x-component
        text/x-cross-domain-policy;
    # 是否在http header中添加Vary: Accept-Encoding,建議開啟
    gzip_vary on;
    # 禁用IE 6 gzip
    gzip_disable "MSIE [1-6]\.";

不同gzip_comp_level的壓縮率可以參考下圖:

gzip對svg和x-icon的壓縮效果比較明顯,一般可以達到50%以上的壓縮效果,但是對于壓縮過的PNG、GIF格式圖片啟用Gzip,反而會因為添加標頭、壓縮字典,增大了圖片的大小。

啟用壓縮后,首頁請求的資源大小由原來的10M降低到2.8M,效果還是比較明顯的。

啟用http緩存

每次訪問網頁時80%的時間都會花在資源下載上,因此使用緩存可以大大提高網頁訪問時的響應速度。

參考H5BP配置目錄下的expires.conf,作為Nginx服務器配置:

# Expire rules for static content
    # No default expire rule. This config mirrors that of apache as outlined in the
    # html5-boilerplate .htaccess file. However, nginx applies rules by location,
    # the apache rules are defined by type. A consequence of this difference is that
    # if you use no file extension in the url and serve html, with apache you get an
    # expire time of 0s, with nginx you'd get an expire header of one month in the
    # future (if the default expire rule is 1 month). Therefore, do not use a
    # default expire rule with nginx unless your site is completely static
    # cache.appcache, your document html and data
    location ~* \.(?:manifest|appcache|html?|xml|json)$ {
      add_header Cache-Control "max-age=0";
    }
    # Feed
    location ~* \.(?:rss|atom)$ {
      add_header Cache-Control "max-age=3600";
    }
    # Media: images, icons, video, audio, HTC
    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ {
      access_log off;
      add_header Cache-Control "max-age=2592000";
    }
    # Media: svgz files are already compressed.
    location ~* \.svgz$ {
      access_log off;
      gzip off;
      add_header Cache-Control "max-age=2592000";
    }
    # CSS and Javascript
    location ~* \.(?:css|js)$ {
      add_header Cache-Control "max-age=31536000";
      access_log off;
    }
    # WebFonts
    # If you are NOT using cross-domain-fonts.conf, uncomment the following directive
    # location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
    #  add_header Cache-Control "max-age=2592000";
    #  access_log off;
    # }

上述配置禁用manifest,appcache,html,xml和json文件的緩存。 它將RSS和ATOM訂閱文件緩存1小時,Javascript和CSS文件1年,以及其他靜態文件(圖像和媒體)1個月。

緩存全部設置為public,所以任何系統都可以緩存它們。 將它們設置為私有將限制它們被私有緩存(例如我們的瀏覽器)緩存。

關于緩存中資源的新鮮度控制可以看這篇文章HTTP緩存控制小結。

總結

這次只是很簡單地對首屏加載進行了性能優化,減少了10個http請求,總資源大小從10.4MB降到2.8MB,首屏DOMContentLoaded時間從12秒左右降到2秒左右,load時間從22秒左右降到6秒左右,效果還是很明顯的。

參考文章

Google Developers中performance系列文章

Front-End Performance Checklist 2018

前端那些事兒」② 極限性能優化

前端性能優化相關

HTTP緩存控制小結

Nginx緩存最佳實踐

 

來自:http://www.iteye.com/news/32894

 

 本文由用戶 grayrover 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!