網頁頁面性能優化總結

  • js性能優化是前端面試一個常問知識點。因此我結合我我的一些經驗,加上看了其餘一些文章點分析。做了一些總結。

一,主要從用戶輸入網址到頁面渲染完成。及與用戶交互到方面來分析。

過程:javascript

  • 用戶輸入網址請求資源 => 將請求到的資源渲染成頁面 => 渲染完成的頁面交互 => 其餘方面的優化
一,用戶輸入網址請求資源
  1. 當用戶輸入一個域名網址時,瀏覽器會將這個域名發送到DNS服務器
    (這一過程當中,咱們能夠經過改變咱們host的配置,將域名配置爲咱們開發環境的服務器ip。實現遠程開發);
  2. 經過DNS服務器進行域名解析,拿到對應的服務器ip地址;
  3. 瀏覽器拿到服務器的ip後,找到對應的服務器;
  • =>這個過程能夠作個http緩存優化(見下文——http緩存)
  1. 獲取服務器js,html等資源;
二,將請求到的資源渲染成頁面
  • =>http頁面加載及渲染過程的優化(見下文——頁面加載及渲染過程)
三,渲染完成的頁面交互
  • =>頁面交互過程的優化(見下文——頁面交互過程的優化)
四,其餘方面的優化
  • =>其餘方面的優化的優化(見下文——其餘方面的優化)

二,http緩存及優化

  1. 強制緩存
不會向服務器發送請求,直接從緩存中讀取資源,
在chrome控制檯的network選項中能夠看到該請求返回200的狀態碼,
而且size顯示from disk cache或from memory cache;
複製代碼
設置強制緩存的方式:
在響應頭設置:
Catch-Control優先級 > Expires優先級

Catch-Control:
好比Cache-Control:max-age=300(秒)
表明在這個請求正確返回時間(瀏覽器也會記錄下來)的5分鐘內再次加載資源,就會命中強緩存

Expires:
好比Expires:Thu,21 Jan 2020 23:39:02 GMT
response header裏的過時時間,瀏覽器再次加載資源時,若是在這個過時時間內,則命中強緩存。
它的值爲一個絕對時間的GMT格式的時間字符串;
存在一個缺點:但因爲服務端時間和客戶端時間可能有偏差,這也將致使緩存命中的偏差,所以如今經常使用這個;
複製代碼
  1. 協商緩存
協商緩存:向服務器發送請求,服務器會根據這個請求的request
header的一些參數來判斷是否命中協商緩存,若是命中,則返回304狀態碼並帶上新的response
header通知瀏覽器從緩存中讀取資源;另外協商緩存須要與cache-control共同使用。;
複製代碼
設置協商緩存的方式:
在響應頭設置:
Etag優先級 > Last-Modified優先級

Etag:
服務器響應請求時,經過此字段告訴瀏覽器當前資源在服務器生成的惟一標識(生成規則由服務器決定);
If-None-Match: 再次請求服務器時,瀏覽器的請求報文頭部會包含此字段,後面的值爲在緩存中獲取的標識。
服務器接收到次報文後發現If-None-Match則與被請求資源的惟一標識進行對比:
a. 不一樣,說明資源被改動過,則響應整個資源內容,返回狀態碼200。
b. 相同,說明資源無意修改,則響應header,瀏覽器直接從緩存中獲取數據信息。返回狀態碼304.
c. 可是實際應用中因爲Etag的計算是使用算法來得出的,而算法會佔用服務端計算的資源,
全部服務端的資源都是寶貴的,因此就不多使用Etag了。

Last-Modified: Fri, 22 Jul 2020 01:47:00 GMT
服務器在響應請求時,會告訴瀏覽器資源的最後修改時間;
if-Modified-Since:
瀏覽器再次請求服務器的時候,請求頭會包含此字段,後面跟着在緩存中得到的最後修改時間。
服務端收到此請求頭髮現有if-Modified-Since,則與被請求資源的最後修改時間進行對比,
若是一致則返回304和響應報文頭,瀏覽器只須要從緩存中獲取信息便可。
從字面上看,就是說:從某個時間節點算起,是否文件被修改了:
a. 若是真的被修改:那麼開始傳輸響應一個總體,服務器返回:200 OK
b. 若是沒有被修改:那麼只需傳輸響應header,服務器返回:304 Not Modified

if-Unmodified-Since:
從字面上看, 就是說: 從某個時間點算起, 是否文件沒有被修改
若是沒有被修改:則開始繼續傳送文件: 服務器返回: 200 OK
若是文件被修改:則不傳輸,服務器返回: 412 Precondition failed (預處理錯誤);

這兩個的區別是一個是修改了才下載一個是沒修改才下載。
Last-Modified 說好卻也不是特別好,由於若是在服務器上,一個資源被修改了,但其實際內容根本沒發生改變,
會由於Last-Modified時間匹配不上而返回了整個實體給客戶端(即便客戶端緩存裏有個如出一轍的資源)。
爲了解決這個問題,HTTP1.1推出了Etag。

複製代碼
  1. 強制緩存優先級 > 協商緩存優先級;css

  2. 刷新html

用戶行爲對瀏覽器緩存的影響
1.地址欄訪問,連接跳轉是正經常使用戶行爲,將會觸發瀏覽器緩存機制;
2.F5刷新,瀏覽器會設置max-age=0,跳過強緩存判斷,會進行協商緩存判斷;
3.ctrl+F5刷新,跳過強緩存和協商緩存,直接從服務器拉取資源。
複製代碼
  1. 緩存的優勢
a. 減小了冗餘的數據傳遞,節省寬帶流量
b. 減小了服務器的負擔,大大提升了網站性能
c. 加快了客戶端加載網頁的速度 這也正是HTTP緩存屬於客戶端緩存的緣由。
複製代碼

三,頁面加載及渲染過程(HTML,Js,css等資源的加載與執行)

  1. 當瀏覽器在解析dom樹的時候,若是遇到script標籤。會阻塞其餘任務的執行。直到script標籤加載,解析完成;
  2. 這個時候頁面會一片空白。用戶體驗很很差,可使用如下作法;
  • => A, 將script標籤放在body的最底部,保證js文件最後加載並執行;同時不影響頁面加載;
  • => B, 或者使用defer,以下寫法。這種方式可使瀏覽器解析到script標籤時,也會加載js。但他會等到dom樹解析完成後再去執行js(DomContentLoader以前執行),所以不會阻塞瀏覽器執行;
<script src="test.js" type="text/javascript" defer></script>
複製代碼
  • => C, 動態的插入script標籤來加載腳本,好比經過如下代碼(參考);
function loadScript(url, callback) {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    // 處理IE
    if (script.readyState) {
      script.onreadystatechange = function () {
        if (script.readyState === 'loaded' || script.readyState === 'complete') {
          script.onreadystatechange = null;
          callback();
        }
      }
    } else {
      // 處理其餘瀏覽器的狀況
      script.onload = function () {
        callback();
      }
    }
    script.src = url;
    document.body.append(script);
  }

  // 動態加載js
  loadScript('file.js', function () {
    console.log('加載完成');
  });
複製代碼
  1. 解析css時。不會操做html元素。所以不會阻塞dom樹的渲染;同時dom樹和css都解析完成後,合併生成渲染樹;
  2. 瀏覽器按照從上到下,從左到右的順序。繪製生成渲染樹。展現頁面給用戶;

四,渲染完成的頁面交互

  1. 滾動條調用接口時,能夠用節流throttle等優化方式,減小http請求;
  2. 輸入搜索時,能夠用防抖debounce等優化方式,減小http請求;
  3. 減小dom元素對操做次數(參考);
// 優化前
  const el = document.getElementById('test');
  el.style.borderLeft = '1px';
  el.style.borderRight = '2px';
  el.style.padding = '5px';
 // 優化後,一次性修改樣式,這樣能夠將三次重排減小到一次重排
  const el = document.getElementById('test');
  el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'
複製代碼
  1. 使用事件委託;
  2. 應該儘量的減小對象成員的查找次數和嵌套深度;
  3. 下降循環遍歷次數(特別對於多維數組的匹配時);
let arr1 = [{id: 12, name: 'aa'}, {id: 33, name: 'aa'}];// => {12: {id: 12, name: 'aa', 33: {id: 12, name: 'aa'}};
let arr2 = [{id: 12, age: '18'}, {id: 33,age: '22' }];
複製代碼

五,其餘方面的優化

  1. 對js,css等資源進行源碼壓縮,減少文件大小;
  2. 合理控制圖片大小,對長期固定圖片使用base64編碼,使用雪碧圖等;
  3. 設置樣式時,儘可能使用className,少用style;
  4. 少用全局變量,避免全局搜索;
  5. 方便時多使用原生方法;
  6. 使用第三方資源時。儘可能作到按需加載;
相關文章
相關標籤/搜索