跟着underscore学防抖

222 阅读2分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。

1.防抖是什么

在事件触发后n秒后执行回调函数,如果n秒内再次触发,则重新计算时间

2.防抖的使用场景

鼠标事件:click,mousemove,mouseover

键盘事件: keydown,keyup

window事件: resize,scroll

以上事件频繁触发就可能引起多次请求或页面卡顿,为了规避这种情况,就需要控制回调函数的执行次数。常见的有防抖和节流,本次介绍underscore的防抖函数。

3.简易版防抖

function debounce(callback,wait=0){
    let timer=null;
  
    return function(){
        let args = arguments;
        let context = this;
        clearTimeout(timer);
        timer= setTimeout(() => {
            callback.apply(context,args)
        }, wait);
    }
}

4.underscore的防抖

/**
 * 
 * @param {*} func 回调函数
 * @param {*} wait 等待时间
 * @param {*} immediate 是否立即执行回调函数
 * @returns 
 */
function debounce(func, wait, immediate) {
  var timeout, previous, args, result, context;

  var later = function() {
    //计算是否超时
    var passed = now() - previous;
    if (wait > passed) {
      //距离上一次调用已经过了passed时间
      timeout = setTimeout(later, wait - passed);
    } else {
      timeout = null;
      if (!immediate) result = func.apply(context, args);
      // This check is needed because `func` can recursively invoke `debounced`.
      if (!timeout) args = context = null;
    }
  };
//处理回调函数的参数
  var debounced = restArguments(function(_args) {
    context = this;
    args = _args;
    previous = now();
    if (!timeout) {
      //第一次的时候,timeout为null。如果immediate=true,立即执行回调函数
      timeout = setTimeout(later, wait);
      
      if (immediate) result = func.apply(context, args);
    }
    return result;
  });

//取消防抖的定时器
  debounced.cancel = function() {
    clearTimeout(timeout);
    timeout = args = context = null;
  };

  return debounced;
}


function restArguments(func, startIndex) {
  startIndex = startIndex == null ? func.length - 1 : +startIndex;
  return function() {
    var length = Math.max(arguments.length - startIndex, 0),
        rest = Array(length),
        index = 0;
    for (; index < length; index++) {
      rest[index] = arguments[index + startIndex];
    }
    switch (startIndex) {
      case 0: return func.call(this, rest);
      case 1: return func.call(this, arguments[0], rest);
      case 2: return func.call(this, arguments[0], arguments[1], rest);
    }
    var args = Array(startIndex + 1);
    for (index = 0; index < startIndex; index++) {
      args[index] = arguments[index];
    }
    args[startIndex] = rest;
    return func.apply(this, args);
  };
}

5.总结

学到了underscore里的防抖原理和设计思想。 防抖在项目中经常用到,一般使用插件的debounce方法或者自己实现一个简易版的。下次对比下lodash的防抖方法。