前端網頁基本效能最佳化

來源:互聯網
上載者:User
這次給大家帶來前端網頁基本效能最佳化,的注意事項有哪些,下面就是實戰案例,一起來看一下。

頁面最佳化

靜態資源壓縮

藉助構建工具(webpack、gulp)適當壓縮圖片、指令碼及樣式等網頁靜態資源。

CSS雪碧圖、base64內聯圖片

將站內小表徵圖合并成一張圖,使用css定位截取對應表徵圖;適當使用內聯圖片。

樣式置頂、指令碼置底

頁面是一個逐步呈現的過程,樣式置頂能更快呈現頁面給使用者;<script> 標籤置頂會阻塞頁面後面資源的下載。

使用外鏈的css和js

多個頁面引用公用靜態資源,資源複用減少額外的http請求。

避免空src的圖片

避免不必要的http請求。

<!-- 空src的圖片依然會發起http請求 --><img src="" alt="image" />

避免在html中縮放圖片

圖片盡量按需求使用指定規格的尺寸,而不是載入一張大圖片再將它縮小。

<!-- 實際圖片尺寸為600x300,在html中縮放為了200x100 --><img src="/static/images/a.png" width="200" height="100" alt="image" />

Preload預先載入

給link標籤的rel設定preload屬性,可以讓瀏覽器在主渲染機制介入前就預先載入資源。這種機制可以更早的擷取資源且不阻塞頁面的初始化。

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <title>Document</title>  <link ref="preload" href="style.css" as="style">  <link ref="preload" href="main.js" as="script">    <link ref="stylesheet" href="style.css"></head><body>    <script src="main.js"></script></body></html>

例子中預先載入了css和js檔案,在之後的頁面渲染中,一旦使用它們就會立即調用。

可指定as的類型載入不同類型的資源。

  1. style

  2. script

  3. video

  4. audio

  5. image

  6. font

  7. document

  8. ...

該方式也可跨域預先載入資源,設定crossorigin屬性即可。

<link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">

CSS

選取器

選取器的優先順序從高到低排列為:

  1. ID選取器

  2. 類別選取器

  3. 標籤選取器

  4. 相鄰選取器

h1 + p{ margin-top: 15px; }

選擇緊接在h1元素後出現的段落,h1和p元素擁有共同的父元素。

子選取器

h1 > strong {color:red;}

後代選取器

h1 em {color:red;}

萬用字元選取器

屬性選取器

*[title] {color:red;}img[alt] {border: 5px solid red;}

偽類別選取器

選取器使用經驗:

  1. 優先選擇類別選取器,可替代多層標籤選取器;

  2. 慎用ID選取器,雖然它效率高,但是在頁面中是唯一的,不利於團隊協作和維護;

  3. 合理利用選取器的繼承性;

  4. 避免css運算式。

減少選取器的層級

建立在上一條選取器的優先順序之上,應盡量避免多層次的選取器嵌套,最好不要超過3層。

.container .text .logo{ color: red; }/*改成*/.container .text-logo{ color: red; }

精簡頁面樣式檔案,去掉不用的樣式

瀏覽器會進行多餘的樣式匹配,影響渲染時間,另外樣式檔案過大也會影響載入速度。

利用css繼承減少代碼量

利用css的可繼承屬性,父元素設定了樣式,子項目就不用再設定。

常見的可以繼承的屬性比如:color,font-size,font-family等;不可繼承的比如:position,display,float等。

屬性值為0時,不加單位

css屬性值為0時,可不加單位,減少代碼量。

.text{ width: 0px; height: 0px; }/*改成*/.text{ width: 0; height: 0; }

JavaScript

使用事件委託

給多個同類DOM元素繫結事件使用事件委託。

<ul id="container">  <li class="list">1</li>  <li class="list">2</li>  <li class="list">3</li></ul>
// 不合理的方式:給每個元素都綁定click事件$('#container .list').on('click', function() {  var text = $(this).text();  console.log(text);});// 事件委託方式:利用事件冒泡機制將事件統一委託給父元素$('#container').on('click', '.list', function() {  var text = $(this).text();  console.log(text);    });

需要注意的是,雖然使用事件委託時都可以將事件委託給document來做,但這是不合理的,一個是容易造成事件誤判,另一個是範圍鏈尋找效率低。應該選擇最近的父元素作為委派物件。

使用事件委託除了效能上更優,動態建立的DOM元素也不需要再綁定事件。

DOMContentLoaded

可在DOM元素載入完畢(DOMContentLoaded)後開始處理DOM樹,不必等到所有圖片資源下載完後再處理。

// 原生javascriptdocument.addEventListener("DOMContentLoaded", function(event) {  console.log("DOM fully loaded and parsed");}, false);// jquery$(document).ready(function() {  console.log("ready!");});// $(document).ready()的簡化版$(function() {  console.log("ready!");});

預先載入和懶載入

預先載入

利用瀏覽器空閑時間積極式載入將來可能會用到的資源,片、樣式、指令碼。

無條件預先載入

一旦onload觸發,立即擷取將來需要用到的資源。

圖片資源預先載入。(3種實現圖片預先載入的方式)。

基於使用者行為的預先載入

對於使用者行為可能進行的操作進行判斷,積極式載入將來可能需要用到的資源。

  1. 當使用者在搜尋輸入框輸入時,積極式載入搜尋結果頁可能用到的資源;

  2. 當使用者去操作一個Tab選項卡時,預設顯示其中一個,當要去點擊(click)其他選項時,在滑鼠hover時,就可先載入將來會用到的資源;

懶載入

除頁面初始化需要的內容或組件之外,其他都可以消極式載入,如剪下圖片的js庫、不在可視範圍的圖片等等。

圖片懶載入。(判斷圖片是否在可視地區範圍內,若在,則將真實路徑賦給圖片)

避免全域尋找

任何一個非局部變數在函數中被使用超過一次時,都應該將其儲存為局部變數。

function updateUI(){  var imgs = document.getElementsByTagName("img");  for (var i=0, len=imgs.length; i < len; i++){    imgs[i].title = document.title + " image " + i;  }  var msg = document.getElementById("msg");  msg.innerHTML = "Update complete.";}

在上面函數中多次使用到document全域變數,尤其在for迴圈中。因此將document全域變數儲存為局部變數再使用是更優的方案。

function updateUI(){  var doc = document;  var imgs = doc.getElementsByTagName("img");  for (var i=0, len=imgs.length; i < len; i++){    imgs[i].title = doc.title + " image " + i;  }  var msg = doc.getElementById("msg");  msg.innerHTML = "Update complete.";}

值得注意的一點是,在javascript代碼中,任何沒有使用var聲明的變數都會變為全域變數,不正當的使用會帶來效能問題。

避免不必要的屬性查詢

使用變數和數組要比訪問對象上的屬性更有效率,因為對象必須在原型鏈中對擁有該名稱的屬性進行搜尋。

// 使用數組var values = [5, 10];var sum = values[0] + values[1];alert(sum);// 使用對象var values = { first: 5, second: 10};var sum = values.first + values.second;alert(sum);

上面代碼中,使用對象屬性來計算。一次兩次的屬性尋找不會造成效能問題,但若需要多次尋找,如在迴圈中,就會影響效能。

在擷取單個值的多重屬性尋找時,如:

var query = window.location.href.substring(window.location.href.indexOf("?"));

應該減少不必要的屬性尋找,將window.location.href緩衝為變數。

var url = window.location.href;var query = url.substring(url.indexOf("?"));

函數節流

假設有一個搜尋方塊,給搜尋方塊綁定onkeyup事件,這樣每次滑鼠抬起都會發送請求。而使用節流函數,能保證使用者在輸入時的指定時間內的連續多次操作只觸發一次請求。

<input type="text" id="input" value="" />
// 綁定事件document.getElementById('input').addEventListener('keyup', function() {  throttle(search);}, false);// 邏輯函數function search() {  console.log('search...');}// 節流函數function throttle(method, context) {  clearTimeout(method.tId);  method.tId = setTimeout(function() {    method.call(context);  }, 300);}

節流函數的應用情境不局限搜尋方塊,比如頁面的滾動onscroll,展開視窗onresize等都應該使用節流函數提升效能。

最小化語句數

語句數量的多少也是影響操作執行速度的因素。

將多個變數聲明合并為一個變數聲明

// 使用多個var聲明var count = 5;var color = "blue";var values = [1,2,3];var now = new Date();// 改進後var count = 5,  color = "blue",  values = [1,2,3],  now = new Date();

改進的版本是只使用一個var聲明,由逗號隔開。當變數很多時,只使用一個var聲明要比單個var分別聲明快很多。

使用數組和對象字面量

使用數組和對象字面量的方式代替逐條語句賦值的方式。

var values = new Array();values[0] = 123;values[1] = 456;values[2] = 789;// 改進後var values = [123, 456, 789];
var person = new Object();person.name = "Jack";person.age = 28;person.sayName = function(){  alert(this.name);};// 改進後var person = {  name : "Jack",  age : 28,  sayName : function(){    alert(this.name);  }};

字串最佳化

字串拼接

早期瀏覽器未對加號拼接字串方式最佳化。由於字串是不可變的,就意味著要使用中間字串來儲存結果,因此頻繁的建立和銷毀字串是導致它效率低下的原因。

var text = "Hello";text+= " ";text+= "World!";

把字串添加到數組中,再調用數組的join方法轉成字串,就避免了使用加法運算子。

var arr = [],  i = 0;arr[i++] = "Hello";arr[i++] = " ";arr[i++] = "World!";var text = arr.join('');

現在的瀏覽器都對字串加號拼接做了最佳化,所以在大多數情況下,加法運算子還是首選。

減少迴流和重繪

在瀏覽器渲染過程中,涉及到迴流和重繪,這是一個損耗效能的過程,應注意在指令碼操作時減少會觸發迴流和重繪的動作。

  1. 迴流:元素的幾何屬性發生了變化,需要重新構建渲染樹。渲染樹發生變化的過程,就叫迴流;

  2. 重繪:元素的幾何尺寸沒有變化,某個元素的CSS樣式(背景色或顏色)發生了變化。

觸發重排或重繪的操作有哪些?

  1. 調整視窗大小

  2. 修改字型

  3. 增加或者移除樣式表

  4. 內容變化,比如使用者在<input/>框中輸入文字

  5. 操作class屬性

  6. 指令碼操作DOM(增加、刪除或修改DOM元素)

  7. 計算offsetWidth和offsetHeight屬性

  8. 設定style屬性的值

如何減少重排和重繪,提升網頁效能?

1、指令碼操作DOM元素

  1. 將DOM元素設定為display:none,設定過程中會觸發一次迴流,但之後可以隨意改動,修改完後再顯示;

  2. 將元素clone到記憶體中再進行操作,修改完後重新替換元素。

2、修改元素的樣式

  1. 盡量批量修改,而不是逐條修改;

  2. 預先設定好id、class,再設定元素的className。

3、為元素添加動畫時將元素CSS樣式設為position:fixed或position:absolute,元素脫離文檔流後不會引起迴流。

4、在調整視窗大小、輸入框輸入、頁面滾動等情境時使用節流函數(上面已提到過)。

HTTP

瀏覽器緩衝

合理設定瀏覽器緩衝是網頁最佳化的重要手段之一。

Expires 和 Cache-Control

Expires出自HTTP1.0,Cache-Control出自HTTP1.1,同時設定兩者時,Cache-Control 會覆蓋 Expires。

  1. Expires指定的是實際到期日期而不是秒數。但Expires存在一些問題,如伺服器時間不同步或不準確。所以最好使用剩餘秒數而不是絕對時間來表達到期時間。

  2. Cache-Control可設定max-age值,單位秒,指定緩衝到期時間。如:Cache-Control: max-age=3600。

ETag 和 Last-Modified

ETag 和 Last-Modified都由伺服器返回在response headers中,其中ETag的優先順序比Last-Modified高,也就是說伺服器會優先判斷ETag的值。

  1. ETag是附加到文檔上的任意標籤,可能是文檔的序號或版本號碼,或者是文檔內容的校正等。當文檔改變時ETag值也會隨之改變。與ETag相關的是 If-None-Match,當瀏覽器發起請求時,會在If-None-Match欄位攜帶ETag的值發給伺服器;

  2. Last-Modified是文檔在伺服器端最後被修改的時間。與Last-Modified相關的是If-Modified-Since,當瀏覽器發起請求時,會在If-Modified-Since欄位攜帶Last-Modified的值發送給伺服器。

強緩衝和協商緩衝

緩衝的類型強緩衝和協商緩衝。兩者區別是,強緩衝不會向伺服器發請求,而協商緩衝會發請求,匹配成功返回304 Not Modified,匹配不成功返回200;瀏覽器會先校正強緩衝,若強緩衝未命中,再進行協商緩衝校正。

如何配置瀏覽器緩衝

  1. 在web伺服器的返迴響應中添加Expires和Cache-Control;

  2. 在nginx或apache的設定檔中配置Expires和Cache-Control。

為什麼要減少HTTP請求

在效能最佳化中減少http請求的措施佔了很大部分,比如:使用css雪碧圖代替多張圖片的請求、避免空src的圖片、使用內聯圖片、使用外鏈的css和js、緩衝等。

從輸入URL到頁面載入完成的過程包括:

  1. DNS解析

  2. TCP串連

  3. HTTP請求與響應

  4. 瀏覽器渲染頁面

  5. 關閉串連

相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!

推薦閱讀:

CSS實戰項目中書寫規範與順序

css+transition做出顯隱動畫

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.