前端進階(14) - 如何提升前端性能和響應速度

如何提升前端性能和響應速度

下面大多是從前端工程化的角度給出的優化建議,如果需要了解語法上的優化,可以參考:

  1. 如何提高頁面加載速度
  2. 編寫高效的JavaScript
  3. Web前端性能優化進階 - 完結篇

1. 原生 css 動畫代替 js 動畫

原生 css 動畫要比 js 實現的動畫要高效很多,所以在可能的情況下儘量用原生 css 動畫。

可以參考:

2. 原生 js 代替第三方庫

因爲第三方庫不可避免的會增大打包文件的體積,並且有很多我們用不着的代碼和性能的損失,所以在可能的情況下儘量用原生 js 的 api,代替第三方庫的 api,比如 jquerylodashunderscoremoment 等。

可以參考:

3. 使用第三方庫時,用子模塊代替整個包

有些第三方庫會比較大,如果提供單個模塊的使用方式,就儘量使用子模塊代替使用整個包,比如 lodashjquery-ui 等。

lodash 爲例:

// 不推薦
import _ from 'lodash';
_.forEach();
_.defaults();

// 推薦
import forEach from 'lodash/forEach';
import defaults from 'lodash/defaults';
forEach();
defaults();

4. 用高效的 api 代替低效的 api

如果相同的功能可以有多種選擇,應當儘量使用高效的一種方案。

比如:

  • document.getElementById, document.getElementsByClassName, document.getElementsByTagName 代替 document.querySelector, document.querySelectorAll
  • el.innerHTML 代替 document.createElement, el.appendChild

5. 扁平結構、避免無用嵌套

避免無用的閉包、無用的塊作用域,儘量是代碼結構扁平化。

比如:

// 低效的實現
const urlParams = (() => {
  const params = {};
  if (location.search) {
    location.search.slice(1).split('&').forEach(item => {
      const [key, value = ''] = item.split('=');
      urlParams[key] = value;
    });
  }
  
 return params;
})();


// 更高效的實現
const urlParams = {};
if (location.search) {
  location.search.slice(1).split('&').forEach(item => {
    const [key, value = ''] = item.split('=');
    urlParams[key] = value;
  });
}

6. 用 es6 的模塊化

現在 js 的模塊化主要是 commonjses6 模塊化規範,但是在開發的時候,建議是用 es6 的模塊化規範,因爲 es6 的模塊化可以使用 Tree Shaking 的功能。

這個功能能夠在構建工具打包代碼時,對代碼進行分析,只有真正用到的代碼會被打包,沒有用到的則不會。

// one.js
export const smile = {};
export const cry = [];

// two.js
import { smile } from './one';
export default smile;

上面的代碼以 two.js 爲入口進行打包,則 one.js 中只有 export const smile = {} 會被打包,而 export const cry = [] 不會。

關於 Tree Shaking,可以參考:

7. 合併、壓縮、分割

代碼的合併與壓縮是前端的必修課,如果使用 webpack 來打包,webpack 會自動幫我們完成,一般無需關心。

另外,在有些時候,代碼是需要做分割的,因爲 webpack 會把代碼都打包到一個文件中,當這個文件很大的時候,就需要分割成多個小文件。一般建議 bundle 文件最大不超過 350k

對於 webpack,可以用 DllPluginSplitChunksPlugin 做文件分割。

8. 按需加載

對於很多應用來說,特別是 SPA 應用,有些資源是沒必要在首屏就加載出來的,而是等到要用的時候才加載,這就是按需加載。按需加載可以減小首屏加載文件的體積,達到提高響應速度的目的。

// about.js
export default render;

// main.js
document.getElementById('about').addEventListener('click', e => {
  import('./about').then(({default: render}) => {
    // 渲染頁面
    render();
  });
}, !1);

上面的代碼中只有當點擊了 #about 元素後,纔會加載 about.js 文件。

可以參考:

9. rollup

前端性能的優化除了從語法、http 協議、工程結構方向之外,構建工具也是一個可以優化的方向。

對於前端開發者來說,基本上都用 webpack 來打包項目,但 webpack 帶給我們強大功能的同時,也會有一些副作用產生,就是會產生很多冗餘的代碼(如果你有查看過 webpack 的 bundle 文件,便會發現)。

如果你的項目不需要處理靜態資源(如圖片),也不需要按需加載,並追求前端高性能的話,可以嘗試 rollup

比如:

源代碼

# 目錄
|-- src/
    |-- index.js
    |-- prefix.js
    |-- suffix.js

    
# prefix.js
const prefix = 'prefix';

export default str => `${prefix} | ${str}`;
    
    
# suffix.js
const suffix = 'suffix';

export default str => `${str} | ${suffix}`;


# index.js
import prefix from './prefix';
import suffix from './suffix';

export default str => suffix(prefix(str)); 

rollup 打包後的代碼:

'use strict';

const prefix = 'prefix';

var prefix$1 = str => `${prefix} | ${str}`;

const suffix = 'suffix';

var suffix$1 = str => `${str} | ${suffix}`;

var index = str => suffix$1(prefix$1(str));

module.exports = index;

webpack 打包後的代碼:

module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/     
/******/     中間有 100 行代碼被省略
/******/     
/******/ ]);

可以參考:

10. prepack

前端性能的優化還有一個方向,就是預編譯腳本,即把原本在運行階段才解析的代碼通過工具預執行,然後只留下結果。

prepack 便是這樣的一個工具,它的思路大致是這樣:

把不依賴外部環境的邏輯提前進行運算,並把運算結果替換到相應的源碼處,然後從源碼中移除這段邏輯。

源代碼

(() => {
  const secondsOfOneDay = 24 * 60 * 60;

  window.getSecondsOfDays = days => days * secondsOfOneDay;
})();

編譯後的代碼

(function () {
  var _$0 = this;

  var _1 = days => {
    return days * 86400;
  };

  _$0.getSecondsOfDays = _1;
}).call(this);

可以參考:

11. css 選擇器不要嵌套太深

對於前端來說,css 對性能影響比較小,所以,這裏只提一點最常見、也是最有效果的建議:選擇器不要嵌套太深。

一般建議選擇器層級在 2 級以內,最多不超過 3 級。

// 下面是 less, scss, css 語法

// 不好
.one {
  .two {
    .three {
      .four {}
    }
  }
}

// 不推薦
.one {
  .two {
    .three {}
  }
}

// 好
.one .two {} 
.one {} 

後續

更多博客,查看 https://github.com/senntyou/blogs

作者:深予之 (@senntyou)

版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章