js函数防抖、节流实现

防抖 Debounce

函数防抖就是,延迟一段时间再执行函数,如果这段时间内又触发了该函数,则延迟重新计算;

//  简单实现
function debounce(fn, wait) {
  let t
  return () => {
    let context = this
    let args = arguments
    if (t) clearTimeout(t)
    t= setTimeout(() => {
        fn.apply(context, args)
    }, wait)
  }
}
// underscore.js debounce
//
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.

_.debounce = function(func, wait, immediate) {
  var timeout, args, context, timestamp, result;

  // 处理时间
  var later = function() {
    var last = _.now() - timestamp;

    if (last < wait && last >= 0) {
      timeout = setTimeout(later, wait - last); // 10ms 6ms 4ms
    } else {
      timeout = null;
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };

节流 throttle

节流:函数间隔一段时间后才能再触发,避免某些函数触发频率过高,比如滚动条滚动事件触发的函数。

// 简单实现
function throttle (fn, wait, mustRun) {
  let start = new Date()
  let timeout
  return () => {
    // 在返回的函数内部保留上下文和参数
    let context = this
    let args = arguments
    let current = new Date()

    clearTimeout(timeout)

    let remaining = current - start
    // 达到了指定触发时间,触发该函数
    if (remaining > mustRun) {
      fn.apply(context, args)
      start = current
    } else {
      // 否则wait时间后触发,闭包保留一个timeout实例
      timeout = setTimeout(fn, wait);
    }
  }
}
// underscore.js throttle
//
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.

_.throttle = function(func, wait, options) {
  var context, args, result;
  var timeout = null;
  var previous = 0;
  if (!options) options = {};
  var later = function() {
    previous = options.leading === false ? 0 : _.now();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
  };
  return function() {
    var now = _.now();
    if (!previous && options.leading === false) previous = now;
    var remaining = wait - (now - previous);
    context = this;
    args = arguments;
    if (remaining <= 0 || remaining > wait) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      previous = now;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining);
    }
    return result;
  };
};

原文地址:https://www.cnblogs.com/sysuhanyf/p/7514108.html