web性能優化指南


前端性能優化,是每個前端必備的技能,優化自己的代碼,使自己的網址可以更加快速的訪問打開,減少用戶等待,今天就會從幾個方面說起前端性能優化的方案,

看下面的一張圖,經常會被面試官問,從輸入URL到頁面加載完成,發生了什么?

 

 

1.用戶輸入www.baidu.com
2.瀏覽器通過DNS。吧url解析ip
3.和ip地址建立TCP連接,發送HTTP請求
4.服務器接收請求,查庫,讀文件等,拼接好 返回的HTTP響應
5.瀏覽器收到首屏html,開始渲染,
6.解析html位dom
7.解析css為css-tree
8.dom+css生成render-tree繪圖
9.加載script的js文件
10.執行js文件
 
DNS緩存
 DNS是“域名系統”的縮寫,它的工作是將域名和主機名轉化為服務器主機的 IP 地址;
  DNS查找流程:瀏覽器緩存 — 本地hosts文件 — 本地DNS解析器緩存 — 本地DNS服務器 — 本地DNS服務器設置(是否設置轉發器)— 根DNS服務器

 瀏覽器緩存之客戶端緩存

    無需請求的memory cache,disk cache;

    需要發請求驗證的Etag、Last-Modified304;

    H5新增的 localStorage、sessionStorage;

  合理利用以上緩存,可以很大程度上提高前端性能。

  網站存在緩存怎么解決?
  1.文件加哈希
       1.上線之后,要求用戶強刷新,這種問題,用文件名加指紋方式解決
       2. a.hash.js  hash是整個a.js文件的md5值,文件內容不變,hash不變,緩存生效
  2.緩存文件怎么解決
   1.加時間戳 <script src="/a.js?_t=xx">
   2.加版本號 <script src="/a.js?_v=1.6"> 比如jq,vue公用庫,內容沒有改變 重新加載
   3.加指紋 但是不產生新文件 <script src="/a.js?h=abcd12sa"> 不能清除Cdn緩存,但是生成新文件,會有問題(html,js那個先上)
   4.最終,誕生最優的產生文件<script src="/a.abcd12sa.js">先上js,在上html webpack build 打包
 
優化策略
 1.長連接
  2.減少文件體積    
   1.js打包壓縮 
      1.無效字符的刪除、剔除注釋、代碼語義的縮減與優化、代碼保護
      2.使用在線網站壓縮、使用 html-minifier 對html 中的 js 進行壓縮、使用uglifyjs2 對 js 進行壓縮
      2.圖片壓縮
      1.把網站上用到的一些圖片整合到一張單獨的圖片中
      3.css壓縮
     1.無效代碼刪除、css語義合並
      2.使用在線網站壓縮、使用 html-minifier 對html 中的 css 進行壓縮、使用clean-css 對 css 進行壓縮
   4.html 壓縮
     1.壓縮在文本文件中有意義但是在HTML中不顯示的字符,包括空格、制表符、換行符、注釋等
      2.使用在線網站壓縮、nodejs提供了html-minifier 工具、后端模板引擎渲染壓縮
   5.開啟 gzip
   6.文件合並

    1.如果不合並 === > 文件與文件之間有插入的上行請求,增加了N - 1 個網絡延遲;受丟包問題影響更嚴重;經過代理服務器時可能會被斷開

    2.如果合並 === > 首屏渲染時間變長; 文件緩存大面積失效

    3.公共庫合並、不同頁面的合並

    4.使用在線網站進行文件合並、使用 nodejs 實現文件合並

 3.減少文件請求次數
      1.雪碧圖
      2.js,css打包
      3.緩存控制
      4.懶加載
 4.減少用戶和服務器的距離
  (地理位置)
       1.cdn  js可以推到cdn緩存上
 5.本地存儲
 6.圖片大小計算
  對於一張 100  100 像素的圖片來說,圖像上有 10000 個像素點,如果每個像素的值是 RGBA 存儲的話,那么也就是說每個像素有 4 個通道,每個通道 1 個字節(8 位 = 1個字節),所以該圖片大小大概為 39KB(10000  * 4 / 1024)。但是在實際項目中,一張圖片可能並不需要使用那么多顏色去顯示,我們可以通過減少每個像素的調色板來相應縮小圖片的大小。
 
 瀏覽器緩存機制
  通過網絡獲取內容及速度緩存慢有開銷巨大,較大相應需要在客戶端與服務器之間進行多次往返通信,這回延遲瀏覽器獲得處理內容的時間,還會增加訪問者流量的費用,因此,緩存重復利用之前獲取的資源能力成為性能優化的一個關鍵方面
  廣義的緩存,可以分為四個,大家對httpcache比較熟悉
      1.Http Cache
      2.Service Worker Cache
      3.Memory Cache
      4.Push Cache

  Http Cache
   瀏覽器大佬:需要獲取main.js,看下強緩存里有沒有
      1.Expires和Cache-Control兩個header來控制強緩存

   2.expires: Mon, 16 Mar 2020 09:50:27 GMT

   3.last-modified: Thu, 15 Feb 2018 14:17:52 GMT

  Memory Cache

    內存緩存,短命,比如常用數據js里,瀏覽器也有自己的策略,base64圖片,體積小的靜態資源

  Service Worker Cache

    是一種獨立於主干線程之外的javascript線程,它脫離於瀏覽器窗體,算是幕后工作,可以實現離線緩存,網絡代理等

圖片優化

  圖片通常是最占用流量的,pc端加載平均圖片大小是600k,簡直比js打包后的文件還大,所以針對圖片的優化,不同場景,使用不同文化的類型
   1. jpg   
    1.有壓縮
       2.體積小,不支持透明
         3.用於背景圖,輪播圖

  2.png

    1.無壓縮,質量高,支持透明
       2.色彩線條更豐富,小圖,比如logo,商品icon
   3.svg
    1.文本,體積小,矢量圖
       2.渲染成本,學習成本
   4.圖片打成雪碧圖,減少http請求次數
 
gzip
  Http壓縮就是以縮小體積為目的,對HTTP內容進行重新編碼的過程
  Gzip壓縮背后的原理,是在一個文本文件中找出一些重復出現的字符串,臨時替換他們,從而、使整個文件變小,根據這個原理,文件找那個代碼重復率越高,那么壓縮的效率越高,使用Gzip收益就越大,反之亦然基本來說Gzip都是服務器干的活,比如nginx
 
本地存儲
  常見本地存儲格式有 cookie  localstroage sessionStroage  indexDB
   1.cookie
      最早,體積先定。性能浪費,所有請求都帶上所有的當前域名的。

    因為 http 請求無狀態,所以需要 cookie 去維持客戶端狀態

    cookie 生成方式:http response header 中的 set-cookie; js 中可以通過document.cookie讀寫cookie

    使用:用於瀏覽器端和服務器端的交互;客戶端自身數據的存儲

    過期時間:expire

    存儲限制:作為瀏覽器存儲,大小4kb左右;需要設置過期時間 expire

    cookie 存儲能力被 localstorage 代替

    httponly 不允許 js 讀寫

    cookie 中在相關域名下面 --- cdn的流量損耗 。 解決:cdn 的域名和主站的域名要分開

  2.Web Storage
      1.存儲量大,不自動發個服務器,js控制
   2.localstroage
     HTML5 設計出來專門用於瀏覽器存儲的
       大小為 5M 左右
     僅在客戶端使用,不和服務端進行通信
     接口封裝較好
     瀏覽器本地緩存方案
   3.sessionStroage
    會話級別的瀏覽器存儲
    大小為 5M 左右
    僅在客戶端使用,不和服務端進行通信
    接口封裝較好
    對於標表單信息的維護
  3.indexDB
      運行在瀏覽器上的非關系型數據庫
  4.pwa
   基於緩存技術的應用模型
     可靠:在沒有網絡的環境中也能提供基本的頁面訪問
    快速:針對網頁渲染及網絡數據訪問有較好的優化
         融入:應用可以被增加到手機桌面,並且和普通應用一樣有全屏、推送等特性

重繪與回流

   回流:當我們對DOM修改引發了DOM幾何尺寸的變化(比如修改元素的寬,高度或者隱藏元素等)時,瀏覽器需要重新計算元素的幾何屬性,(其他元素的幾何屬性和位置也會因此受到影響),然后再將計算的結果繪制出來,這個過程就是回流(也加重排)
 
   重繪:當我們對DOM的修改導致了樣式的變化,卻並未影響幾何屬性,(比如修改了顏色和背景色)時,瀏覽器不需要重新計算元素的幾何屬性,直接為該元素繪制新的樣式,(跳過了上圖所示的回流環節)。這個過程叫做重繪
 
  由此我們可以看出,重繪不一定導致回流,回流一定導致重繪
 
  回流是影響最大的
      1.窗體,字體大小
      2.增加樣式表
      3.內容變化
      4.class屬性
      5.offserWidth和offsetHeight
      6.fixed
節流和防抖
  節流
    預定一個函數只有在大於等於執行周期時才執行,周期內調用不執行
// 函數節流  每隔多少時間執行一次
        const throttle = (func ,wait = 100) =>{
            // 無論調用多少次,函數都是100毫秒執行一次
            let lastTime =0;
            return(...args) =>{
                let now = new Date().getTime()
                if(now - lastTime >wait) {
                    func.apply(this.args)
                    lastTime = now
                }
            }
        }

        let i =1;
        window.addEventListener('scroll',throttle(()=>{
            // 使用做圖片懶加載
            console.log(i)
            i+=1
        },350)) 

  

  防抖
    在函數需要頻繁觸發時,只有當有足夠空閑的時間時,才執行一次
/* 
            校驗用戶是不是重復,用戶輸入完,向后端發送請求
            如果用戶每次輸入,都發生請求,造成請求過多
            用戶停止輸入字符串350毫秒,在發出
        */

        const debounce = (func,wait = 350) =>{
            let timer =0;
            return (...args)=>{
                if(timer) {
                    clearInterval(timer)
                }
                timer = setTimeout(() => {
                    func.apply(this,args)
                }, wait);
            }
        }

        let i =1;
        window.addEventListener('scroll',debounce(()=>{
            // 驗證
            console.log(i)
            i+=1
        },350))

  lazy-load

  對於一些圖片多,頁面長的網頁來說,如果每次打開頁面加載全部的網頁內容,頁面加載速度勢必會受到影響,如果每次打開網頁只將網頁可視區域的內容加載給用戶 ,將大大提高網頁瀏覽速度,同時也減輕服務器負載,我們可以使用lazyload.js來實現對圖片的延遲加載,當網頁圖片進入到瀏覽器可視區域時,才會去請求服務器加載圖片。

  

// 獲取所有的圖片
        const img = document.getElementsByTagName('img')
        // 獲取可視區域的高度
        const viewHeight = window.innerHeight || document.documentElement.clientHeight;
        // num用於計算當前顯示到那一張圖片,避免每次都是從第一張開始檢查是否漏出
        let num =0;
        function lazyload() {
            for(let i=num;i<img.length;i++) {
                // 用可是區域高度減去元素頂部距離可視區域頂部的高度
                let distance = viewHeight - img[i].getBoundingClientRect().top
                // 如果可視區域高度大於等於元素頂部距離可視區域頂部的高度,說明元素露出
                if(distance >=0) {
                    // 給元素寫入真實的src,展示圖片
                    img[i].src = img[i].getAttribute('data-src')
                    // 前i張圖片已經加載完畢,,下次從第i+1張開始檢查是否露出
                    num = i+1
                }
            }
        }
        // 監聽scroll
        window.addEventListener('scroll',lazyload,false)

 

performance.getEntriesByType('navigation')  性能檢測

  通過在瀏覽器控制台輸入這個命令,就可以檢測到網頁加載數據,檢測網頁加載性能

  

 

 

 

  列入:
      DNS查詢耗時 通過使用domainLookupEnd - domainLookupStart  就等於dns查詢的時間
      TCP鏈接耗時  通過 connectEnd - connectStart
      HTTP請求耗時 通過 responseEnd - responseStart 
      解析dom樹耗時  通過 domComplete -  domInteractive
      白屏時間 通過 responseStart  - navigationStart
      DOMready時間 通過 domContentLoadedEventEnd - navigationStart
      onload時間 通過 loadEventEnd -  navigationStart 也即是onload回調函數執行的時間
 
Lighthouse插件
Lighthouse分析web應用程序和web頁面,收集關於開發人員最佳實踐的現代性能指標和見解,讓開發人員根據生成的評估頁面,來進行網站優化和完善,提高用戶體驗。
  1.可以在谷歌商店安裝一個Lighthouse一個插件就可以了,下面我是檢測github網站的數據
  2.使用node全局安裝
npm install -g lighthouse

  安裝完之后運行,也是找的github網址,運行成功之后,會彈出一個生成的html頁面。

 

 生成一個html文件,找到然后直接打開就行

 

 

 

 瀏覽器渲染

  

  1.在這一步瀏覽器執行了所有的加載解析邏輯,在解析HTML的過程中發出了頁面渲染所需要的各種外部資源請求
  2.瀏覽器將識別並加載所有的css樣式信息與dom樹合並,最終勝出頁面render樹,(:after :brfore這樣的偽元素在這個環節被構建到DOM樹中)
  3.頁面中所有元素相對位置信息,大小等信息均在這一步得到計算
  4.在這一步瀏覽器會根據我們的DOM代碼結果,把每一個頁面圖層轉換為像素,並對所有的媒體文件進行解碼
  5.最后一步瀏覽器會合並各個圖層,講數據有CPU輸給GPU最終繪制在屏幕上,(復雜的視圖會給這個階段GPU計算帶來一些壓力,在實際中是為了優化動畫性能,我們有時候會手動區分各個視圖)
 
  渲染過程說白了,首先是基於HTML構建一個DOM樹,這顆DOM樹與css解析器解析除的CSSOM相結合,就有了布局渲染樹,最后瀏覽器以布局渲染樹為藍本,去計算布局並繪制圖像,我們頁面初次渲染就大功告成了。
   
  之后每當一個新元素加入到這個DOM樹中,瀏覽器便會通過css引擎查遍css樣式表,找到符合該元素的樣式應用到這個元素上,然后在重新去繪制他
 
服務端渲染 等等.....
以上就是所總結的常見的前端性能優化,如有不足,希望大佬多多指點指點
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM