[TOC]
## 前端性能優化
### `css` 樣式優化
* 當一個屬性只有一個值需要修改時,盡量只設置這一個屬性值
例如:
~~~
// 不推薦使用
background: '#fff'
// 推薦使用
background-color: '#fff'
~~~
* 在設置多個樣式時,盡量避免設置行內樣式;使用更改 `className` 的方式替換 `style.xxx = xxx`
> why: 每次修改元素的style屬性都可能會觸發回流操作,使用className更改可多次創建,一次更改
~~~
// 例如: 在服務的狀態發生改變時,我們需要更改相應標簽的樣式
watch: {
?status(newVal) {
? ?switch(newVal) {
? ? ?case '運行':
? ? ? ?this.serviceClass = 'run';
? ? ? ?break;
? ? ?......
? }
}
}
~~~
### `DOM` 優化
* 盡量減少 `DOM` 元素數量
~~~
// 查看當前頁面dom元素數量
console.log('number of elements', document.getElementsByTagName( '*' ).length)
// 正常頁面的 `dom` 元素數量一般不應該超過1000個
~~~
* 優化 `DOM` 交互
對于只會渲染一次的數值,在 `vue` 中應盡量使用 `v-once` 指令
~~~
<p v-once>這個將不會改變: {{ msg }}</p>
~~~
* 區分 `v-show` 與 `v-if` 的使用
> 在隱藏元素時,前者只會設置樣式 `display: none` ,后者會移除元素
### `HTML` 優化
* 避免空的 `src` 和 `href`
> 為空時,瀏覽器渲染時會把當前頁面的url作為它們的屬性值,從而把頁面的內容加載進來作為它們的值
* 合理架構,使DOM結構盡量簡單
* 利用 `LocalStorage` 合理緩存資源
### 內存優化
JavaScript存在內存回收機制,可將一些不再使用的變量,方法銷毀,釋放其占用的內存。在某些情況下,無法被回收(函數執行完畢后,在函數內部所聲明的對象不一定會被銷毀)
* 變量優化
* 盡量選用局部變量而不是全局變量(回收機制很難判斷何時回收全局變量;局部變量訪問速度更快)
* 善用回調
除了使用閉包訪問內部變量,我們還可使用回調函數處理
優點:回調函數本身通常為臨時的匿名函數,被請求執行后,回調函數自身的引用會被解除,同時得到回收。
~~~
const getData = callback => {
?const data = "some big data";
?callback(data);
}
getData(data => {
?console.log("data:", data);
})
~~~
* 對象優化
* 減少不必要的對象創建
復雜的 `javaScript` 對象,其創建時時間和空間的開銷都很大,應該盡量考慮創建后進行存儲。
### 類型轉換
* 將數字轉為為字符串
從性能上講,`"" + 1` 效率最高,`"" + 1` > `String()` > `.toString()` > `new String()`
~~~
// String() 屬于內部函數,所以速度很快
// .toString() 需要查詢原型中的函數,所以速度略慢
~~~
* 浮點數轉換為整數
錯誤使用 `parseInt()`
~~~
` parseInt 是將字符串轉換為數字,而不是浮點數轉為整型的方法 `
~~~
應該使用 `Math.floor()` 或者 `Math.round()`
~~~
// Math.floor() 返回小于等于參數的最大整數
Math.floor(5.5) // 5
Math.floor(-1.5) // -2
// Math.round() 四舍五入返回整數
Math.round(5.5) // 6
Math.round(-1.5) // -1
Math.round(-1.6) // -2
~~~
### 邏輯判斷優化
* `switch` 語句
在 `if-else` 語句中,當 `else-if` 有至少兩個時,轉換為 `switch` 語句
> tips: 在case中未寫break時會繼續向下執行代碼, 這在需要判斷的選項的值一致時起作用。
~~~
let result = ''
const now = new Date()
const day = now.getDay()
switch(day) {
?case 0:
?case 6:
? ?result = '休息日'
? break
?case 1:
result = '周一'
? ?break
?// ...
?default:
break
}
~~~
### 數組優化
* 初始化數組直接使用 `const arr = [];` ,不要使用 `const arr = new Array();`
* 在遍歷數組時,可先保存數組長度到局部變量,避免多次查詢數組長度(針對 ie 舊版本)
~~~
const length = arr.length;
for (let i = 0; i < length; i++) {}
~~~
### 動畫優化
* 設置動畫元素 `display` 為 `absolute` 或 `fixed`
這樣做只會觸發 `repaint` , 通常情況下會造成頻繁的 `reflow`
### 緩存過期設置
* 在使用localStorage、session等緩存技術時,可設置他們的過期時間,以定期清理一些數據。
例如:
~~~
// 以localstorage為例
class LocalStorage {
?constructor() {
? ?this.source = window.localStorage;
? ?this.init();
}
?init() {
? ?const reg = /__time/;
? ?const data = this.source;
? ?const list = Object.keys(data);
? ?const time = new Date().getTime();
? ?if(list.length > 0){
? ? ?list.forEach(item => {
? ? ? ?if (reg.test(item)) {
? ? ? ? ?if (data[item] < time) {
? ? ? ? ? ?const k = item.replace(reg, "")
? ? ? ? ? ?this.remove(k);
? ? ? ? ? ?this.remove(item);
? ? ? ? }
? ? ? }
? ? })
? };
}
?save(k, v, needTime = false, endTime = 3 * 1000) {
? ?localStorage.setItem(k, v);
? ?if (needTime) {
? ? ?const time = new Date().getTime() + endTime;
? ? ?localStorage.setItem(`${k}__time`, time);
? }
}
?remove(k) {
? ?localStorage.removeItem(k);
}
}
~~~
### 首屏優化
前言:大多時候工程的首頁數據來源于接口,在接口調用獲取到數據前會造成頁面空白的顯示效果,這是不友好的
優化:設置初始空數據:先用空數據占位 html 空間,在獲取到數據后用數據填充到空間中,這樣的話,不會造成視圖重排,只會在對應的空間進行視圖重繪。顯示效果上也會好很多。
## 小結
前端涉及到的性能優化問題,大多是由編碼習慣導致的,多注意一些細節上的代碼編寫,可大幅度的優化性能上的問題。多看一些 “大佬” 的代碼,會提高自己代碼的編寫質量。同時,代碼走查也是個不錯的方式,自檢或協助檢查亦可以提高代碼編寫質量,去除一些不好的書寫習慣。