防抖和节流

171 阅读1分钟

通常,在高频触发的场景下需要防抖和节流,例如:用户疯狂点击按钮、滚动事件、输入模糊匹配等。

防抖思路:也就是说,在某次高频触发下,我们只识别一次(可以控制识别第一次还是最后一次)。假设我们规定500ms内触发多次算高频触发,那么,在500ms内,我们只是别一次。

function debounce(fn, wait, immediate) {//wait:触发间隔时间,immediate为true在开始触发,false在结束时触发
  //判断参数是否合法
  if (typeof (fn) !== 'function') throw new TypeError(`${fn} must be an function`);
  if (typeof (wait) === undefined) wait = 500;
  if (typeof (wait)  === 'boolean') {
      immediate = wait;
      wait = 500;
  }
  if (typeof (immediate) !== 'boolean') immediate = false;

  //设置定时器返回标识
  let timer = null;
  //在proxy中根据频率管控handle的执行次数
  return function proxy(...args) {//传入事件对象
      let self = this,
          now = immediate && !timer;

      //以最后一次点击为准 触发函数
      clearTimeout(timer);
      timer = setTimeout(function () {
          timer = null;
          !immediate ? fn.call(self, ...args) : null;//将this和事件对象传给handle
      }, wait);

      //第一次触发就立即执行
      now ? fn.call(self,...args) : null;
  }
}
function handle(ev) {
  //写自己的业务逻辑
  console.log(this, ev);
}
submit.addEventListener('click', debounce(handle, 1000, true));

节流思路:在某次高频触发下,我们不只识别一次,按照我们设定的间隔时间,每达到这个频率都会触发一次。假设我们规定频率是500ms,我们操作了10min,触发的次数 =(10* 60 *1000)/500。

function throttle(fn, wait){
    if (typeof (fn) !== 'function') throw new TypeError(`${fn} must be an function`);
    if (typeof (wait) === undefined) wait = 500;

    let timer = null,
        previous = 0;//记录上一次操作时间
    return function proxy(...args){
        let self = this,
            now = new Date(),//当前触发操作的时间
            remaining = wait - (now - previous);
        if(remaining <= 0){
            //两次间隔超过wait了,直接执行即可
            clearTimeout(timer);
            timer = null;
            previous = now;
            fn.call(self,...args);
        }else if(!timer){
            //两次触发的间隔时间没有超过wait,则设置定时器,让其等待remaining这么久之后执行一次,前提是没有设置定时器
            timer = setTimeout(function(){
                clearTimeout(timer);
                timer = null;
                fn.call(self,...args);
            },remaining);
        }

    }
}
function demo(ev){
    console.log('ok');
}
window.onscroll = throttle(demo,500);