Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

函数节流&函数去抖 #5

Open
LuanMingyang opened this issue Aug 20, 2018 · 0 comments
Open

函数节流&函数去抖 #5

LuanMingyang opened this issue Aug 20, 2018 · 0 comments

Comments

@LuanMingyang
Copy link
Owner

函数节流&函数去抖

1. 什么是函数节流,函数去抖?

函数节流(throttle):让函数在指定的时间段内周期性地间断执行

函数去抖(debounce):让函数只有在过完一段时间后并且该段时间内不被调用才会被执行

一种很好理解的比喻:

就像一窝蜂的人去排队看演出,队伍很乱,看门的老大爷每隔1秒让进一个人,这个叫throttle;如果来了这一窝蜂的人,老大爷一次演出只让进一个人,下次演出才让下一个人进,这个就叫debounce

函数节流适用场合:

  • DOM 元素的拖拽功能原生实现(mousemove)
  • 游戏中的刷新率
  • scroll/resize

函数去抖:

  • 搜索联想(keyup)
  • 多次提交(commit)的场景,如点击按钮提交发送请求的情况

函数节流和函数去抖的核心就是限制某一个方法被频繁触发,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。

2. 实现函数节流

/**
 * @param  {function}   func      回调函数
 * @param  {number}     wait      表示时间窗口的间隔
 * @param  {object}     options   如果想忽略开始函数的调用,传入{leading: false}。
 *                                如果想忽略结尾函数的调用,传入{trailing: false}
 *                                两者不能共存,否则函数不能执行
 * @return {function}             返回调用函数   
 */
function throttle(func, wait, options) {
  let context, args, timeout, result;
  let previous = 0;
  if (!options) options = {};

  let later = function () {
    previous = options.leading === false ? 0 : +new Date();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
  }

  let throttled = function () {
    context = this;
    args = arguments;

    let now = +new Date();
    if (!previous && options.leading === false) previous = now;
    let remaining = wait - (now - previous); // 距离下次触发的剩余时间
    if (remaining <= 0) {
      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;
  }

  throttled.cancel = function() {
    clearTimeout(timeout);
    previous = 0;
    timeout = null;
  }

  return  throttled;
}

完整代码

3. 实现函数防抖

/**
 * @param  {function} func        回调函数
 * @param  {number}   wait        表示时间窗口的间隔
 * @param  {boolean}  immediate   是否立即调用函数,设置为ture时立即调用
 * @return {function}             返回调用函数
 */
function debounce(func, wait, immediate) {
  let timeout, result;

  let debounced = function() {
    let context = this;
    let args = arguments;

    if (timeout) clearTimeout(timeout);

    if (immediate) {
      let callNow = !timeout;
      timeout = setTimeout(function() {
        timeout = null;
      }, wait);
      if (callNow) {
        result = func.apply(context, args);
      }
    } else {
      timeout = setTimeout(function() {
        func.apply(context, args);
      }, wait);
    }

    return result;
  };

  debounced.cancel = function() {
    clearTimeout(timeout);
    timeout = null;
  }

  return debounced;
}

完整代码

参考:

  1. 如何不择手段提升scroll事件的性能
  2. JavaScript 函数节流和函数去抖应用场景辨析
  3. JavaScript专题之跟着underscore学防抖
  4. JavaScript专题之跟着underscore学节流
  5. underscore.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant