前端性能优化——debounce

实现一个搜索功能,当输入框中的文字改变时,就去请求结果。

一开始是这样写的:



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

但存在很大的问题,仅输入"数学"两个字就会使得keydown事件触发7次,发7次请求。



通过上图可以看出,搜索内容稍有改变就会发新的请求,导致请求过于频繁。但这些请求中真正有用的其实是最后一个,最有一个请求发出时我们已经输入完完整的搜索词,请求的结果也是我们真正想搜索的。前面的请求都是没有意义的,是对网络资源的浪费。

为了让请求不那么频繁,利用setTimeout做了一下处理:



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

以上代码就是当搜索内容改变时,不是立即去请求,而是等500ms之后再去请求,这样的话这500ms之内的改变都会被当成一个改变去发起请求,减少了一定的请求数。


可以看出请求数量确实减少了,但是还是存在无意义的请求。虽然将延迟的时间调大可以更有效的减少请求数,但是会导致输入结束后等待结果的时间变长,体验很不好。

推荐的解决方案:debounce(防抖)。debounce在事件和函数执行之间加了一个控制层,来控制函数的执行次数。

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



// 一定要注意,debounce只执行一次,执行后的函数作为事件处理函数
GOOD:
search = debounce(requestSearchResult(), 500); 
BAD:
search = () => {
    debounce(requestSearchResult(), 500)(); 
}

使用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

除了实时的输入请求外,涉及到 window.resize触发的一些请求或操作也很适合debounce大显身手。

欲了解更多,可阅读实例解析防抖动(Debouncing)和节流阀(Throttling)。

你可能感兴趣的:(前端性能优化——debounce)