網站性能優化

網站性能優化是必須的技能,並且須要長期積累,如下是我本身總結的一些性能優化的策略,主要分爲幾個方面:javascript

  1. 網絡請求優化
  2. 頁面渲染優化
  3. JS阻塞性能與內存泄漏
  4. 負載均衡

1 網絡請求優化

1.1 瀏覽器緩存

瀏覽器在向服務器發起請求前,會先查詢本地是否有相同的文件,若是有,就會直接拉取本地緩存,這和咱們在後臺部署的Redis、Memcache相似,都是起到了中間緩衝的做用,咱們先看看瀏覽器處理緩存的策略:php

瀏覽器默認的緩存是放在內存內的,內存裏的緩存會由於進程的結束或者說瀏覽器的關閉而被清除,而存在硬盤裏的緩存纔可以被長期保留下去。不少時候,咱們在network面板中各請求的size項裏,會看到兩種不一樣的狀態:from memory cache 和 from disk cache,前者指緩存來自內存,後者指緩存來自硬盤。而控制緩存存放位置的,不是別人,就是咱們在服務器上設置的Etag字段。在瀏覽器接收到服務器響應後,會檢測響應頭部(Header),若是有Etag字段,那麼瀏覽器就會將本次緩存寫入硬盤中。css

以Nginx爲例,設置Etaghtml

etag on;   //開啓etag驗證
expires 14d;    //設置緩存過時時間爲14天
複製代碼

打開咱們的網站,在chrome devtools的network面板中觀察咱們的請求資源,若是在響應頭部看見Etag和Expires字段,就說明咱們的緩存配置成功了。java

在咱們配置緩存時必定要切記,瀏覽器在處理用戶請求時,若是命中強緩存,瀏覽器會直接拉取本地緩存,不會與服務器發生任何通訊,也就是說,若是咱們在服務器端更新了文件,並不會被瀏覽器得知,就沒法替換失效的緩存。因此咱們在構建階段,須要爲咱們的靜態資源添加md5 hash後綴,避免資源更新而引發的先後端文件沒法同步的問題。webpack

1.2 資源打包壓縮

咱們以前所做的瀏覽器緩存工做,只有在用戶第二次訪問咱們的頁面才能起到效果,若是要在用戶首次打開頁面就實現優良的性能,必須對資源進行優化。咱們常將網絡性能優化措施歸結爲三大方面:減小請求數、減少請求資源體積、提高網絡傳輸速率。如今,讓咱們逐個擊破:nginx

以Webpack爲例web

  • 壓縮JS
new webpack.optimize.UglifyJsPlugin()
複製代碼
  • 壓縮Html
new HtmlWebpackPlugin({
            template: __dirname + '/views/index.html', // new 一個這個插件的實例,並傳入相關的參數
            filename: '../index.html',
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeRedundantAttributes: true,
                useShortDoctype: true,
                removeEmptyAttributes: true,
                removeStyleLinkTypeAttributes: true,
                keepClosingSlash: true,
                minifyJS: true,
                minifyCSS: true,
                minifyURLs: true,
            },
            chunksSortMode: 'dependency'
        })
複製代碼

咱們在使用html-webpack-plugin 自動化注入JS、CSS打包HTML文件時,不多會爲其添加配置項,這裏我給出樣例,你們直接複製就行。chrome

PS:這裏有一個技巧,在咱們書寫HTML元素的src 或 href 屬性時,能夠省略協議部分,這樣也能簡單起到節省資源的目的。後端

  • 壓縮CSS

在使用webpack的過程當中,咱們一般會以模塊的形式引入css文件(webpack的思想不就是萬物皆模塊嘛),可是在上線的時候,咱們還須要將這些css提取出來,而且壓縮,這些看似複雜的過程只須要簡單的幾行配置就行

const ExtractTextPlugin = require('extract-text-webpack-plugin')
module: {
        rules: [..., {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
                fallback: 'style-loader',
                use: {
                    loader: 'css-loader',
                    options: {
                        minimize: true
                    }
                }
            })
        }]
    }
複製代碼
  • 使用webpack3的新特性:ModuleConcatenationPlugin
new webpack.optimize.ModuleConcatenationPlugin()
複製代碼
  • 把prod環境的shouldUseSourceMap設置爲false,去掉build生成的map文件
devtool: shouldUseSourceMap ? 'source-map' : false,
複製代碼

最後,咱們還應該在服務器上開啓Gzip傳輸壓縮,它能將咱們的文本類文件體積壓縮至原先的四分之一,效果立竿見影,仍是切換到咱們的nginx配置文檔,添加以下兩項配置項目:

gzip on;
gzip_types text/plain application/javascriptapplication/x-javascripttext/css application/xml text/javascriptapplication/x-httpd-php application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
複製代碼

若是你在網站請求的響應頭裏看到這樣的字段,那麼就說明我們的Gzip壓縮配置成功啦:

【!!!特別注意!!!】不要對圖片文件進行Gzip壓縮!不要對圖片文件進行Gzip壓縮!不要對圖片文件進行Gzip壓縮!我只會告訴你效果拔苗助長,至於具體緣由,還得考慮服務器壓縮過程當中的CPU佔用還有壓縮率等指標,對圖片進行壓縮不但會佔用後臺大量資源,壓縮效果其實並不可觀,能夠說是「弊大於利」,因此請在gzip_types 把圖片的相關項去掉。針對圖片的相關處理,咱們接下來會更加具體地介紹。

1.3 圖片資源優化

  • 不要在HTML裏縮放圖像
  • 使用雪碧圖(CSS Sprite)
  • 使用字體圖標(iconfont)

1.4 使用CDN

使用CDN存放靜態資源,避免帶寬爆炸以及加快資源下載.

2 頁面渲染性能優化

2.1 減小重繪和迴流

  • CSS屬性讀寫分離:瀏覽器每次對元素樣式進行讀操做時,都必須進行一次從新渲染(迴流 + 重繪),因此咱們在使用JS對元素樣式進行讀寫操做時,最好將二者分離開,先讀後寫,避免出現二者交叉使用的狀況。最最最客觀的解決方案,就是不用JS去操做元素樣式,這也是我最推薦的。
  • 經過切換class或者使用元素的style.csstext屬性去批量操做元素樣式。
  • DOM元素離線更新:當對DOM進行相關操做時,例、appendChild等均可以使用Document Fragment對象進行離線操做,帶元素「組裝」完成後再一次插入頁面,或者使用display:none 對元素隱藏,在元素「消失」後進行相關操做。
  • 將沒用的元素設爲不可見:visibility: hidden,這樣能夠減少重繪的壓力,必要的時候再將元素顯示。
  • 壓縮DOM的深度,一個渲染層內不要有過深的子元素,少用DOM完成頁面樣式,多使用僞元素或者box-shadow取代。
  • 圖片在渲染前指定大小:由於img元素是內聯元素,因此在加載圖片後會改變寬高,嚴重的狀況會致使整個頁面重排,因此最好在渲染前就指定其大小,或者讓其脫離文檔流。
  • 對頁面中可能發生大量重排重繪的元素單獨觸發渲染層,使用GPU分擔CPU壓力。(這項策略須要慎用,得着重考量以犧牲GPU佔用率爲代價可否換來可期的性能優化,畢竟頁面中存在太多的渲染層對於GPU而言也是一種沒必要要的壓力,一般狀況下,咱們會對動畫元素採起硬件加速。)

2.2 減小頁面從新渲染以及Dom嵌套

  • 以React爲例,若是會引發頁面State變化的,最好在shouldComponentUpdate進行處理,避免每次props或者state更新的時候都從新渲染,若是頁面主要用來顯示的話,可使用PureComponent代替Component,注意PureComponent對於引用類型的變化,不會從新渲染。巧用Fragment代替Component,減小Dom嵌套。

3 JS阻塞性能與內存泄漏

3.1 巧用JS的防抖與節流

函數防抖:將幾回操做合併爲一此操做進行。原理是維護一個計時器,規定在delay時間後觸發函數,可是在delay時間內再次觸發的話,就會取消以前的計時器而從新設置。這樣一來,只有最後一次操做能被觸發。

function debounce(fn, wait) {
    var timeout = null;
    return function() {
        if(timeout !== null) 
                clearTimeout(timeout);
        timeout = setTimeout(fn, wait);
    }
}
複製代碼

函數節流:使得必定時間內只觸發一次函數。原理是經過判斷是否到達必定時間來觸發函數。

var throttle = function(func, delay) {
            var prev = Date.now();
            return function() {
                var context = this;
                var args = arguments;
                var now = Date.now();
                if (now - prev >= delay) {
                    func.apply(context, args);
                    prev = Date.now();
                }
            }
        }
複製代碼

區別: 函數節流無論事件觸發有多頻繁,都會保證在規定時間內必定會執行一次真正的事件處理函數,而函數防抖只是在最後一次事件後才觸發一次函數。 好比在頁面的無限加載場景下,咱們須要用戶在滾動頁面時,每隔一段時間發一次 Ajax 請求,而不是在用戶停下滾動頁面操做時纔去請求數據。這樣的場景,就適合用節流技術來實現。

3.2 內存泄漏

  • 閉包內存泄漏Pattern
  • 在某個頁面(SPA)WillUnMount的時候,記得關閉一些資源,例如WebSocket的斷開,eChart對象置空等。

4 負載均衡

  1. 使用PM2管理多進程
  2. Nginx作反向代理
  3. Docker管理多個容器
相關文章
相關標籤/搜索