天天看點

前端性能優化——debounce

實作一個搜尋功能,當輸入框中的文字改變時,就去請求結果。

一開始是這樣寫的:

<input type="text" onkeydown={search} />

search = () => {
  requestSearchResult();
}
           

但存在很大的問題,僅輸入"數學"兩個字就會使得keydown事件觸發7次,發7次請求。

前端性能優化——debounce

通過上圖可以看出,搜尋内容稍有改變就會發新的請求,導緻請求過于頻繁。但這些請求中真正有用的其實是最後一個,最有一個請求發出時我們已經輸入完完整的搜尋詞,請求的結果也是我們真正想搜尋的。前面的請求都是沒有意義的,是對網絡資源的浪費。

為了讓請求不那麼頻繁,利用setTimeout做了一下處理:

<input type="text" onkeydown={search} />

search = () => {
    setTimeout (() => {
        requestSearchResult();
    }, 500);
}
           

以上代碼就是當搜尋内容改變時,不是立即去請求,而是等500ms之後再去請求,這樣的話這500ms之内的改變都會被當成一個改變去發起請求,減少了一定的請求數。

前端性能優化——debounce

可以看出請求數量确實減少了,但是還是存在無意義的請求。雖然将延遲的時間調大可以更有效的減少請求數,但是會導緻輸入結束後等待結果的時間變長,體驗很不好。

推薦的解決方案:debounce(防抖)。debounce在事件和函數執行之間加了一個控制層,來控制函數的執行次數。

var debounce = require('lodash.debounce');

<input type="text" onkeydown={search} />

// 一定要注意,debounce隻執行一次,執行後的函數作為事件處理函數
GOOD:
search = debounce(requestSearchResult(), 500); 
BAD:
search = () => {
    debounce(requestSearchResult(), 500)(); 
}
           
前端性能優化——debounce

使用debounce之後,它隻會在最後一次改變發生後才會去執行函數,隻發送一次請求。

Lodash和underscore都有debounce的API,可以直接拿來用,以下是loadash.debounce使用方法:

npm i --save lodash.debounce

var debounce = require('lodash.debounce');
           

以下是網上看到的用es6實作的debounce代碼:

export default function debounce(func, wait, immediate) {
  let timeout
  return function(...args) {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
      timeout = null
      if (!immediate) func.apply(this, args)
    }, wait)
    if (immediate && !timeout) func.apply(this, [...args])
  }
}
           

上面的代碼也是可以有效減少請求數量,但是并不能将請求數量減到1,還是會有一些無謂的請求。建議用Lodash和underscore。

繼續閱讀