Stabilizer (Debounce) and the throttle (throttling)

Stabilizer (Debounce) and the throttle (throttling)

1, image stabilization and the reason appears throttling

Image stabilization and can not keep the throttle response is triggered for both solutions the frequency of such problems.

  • When bind to DOM events, some events we can not control the trigger frequency. Such as a mouse motion events onmousemove, scroll bar event onscroll, window size change event onresize, instant operations will result in a high frequency of these events will be triggered. If the callback event is more complex, it will lead to trigger response can not keep up, the page appears Caton, the phenomenon of suspended animation.

  • In real-time check the input, if we bind onkeyup event made a request to the server to check user input process, the event will trigger frequency is high, it will lead to a large number of requests made, the response will greatly speed to keep up with the trigger.

ps: the role and image stabilization function to prevent the throttle is called multiple times. The difference is that, suppose a user of this function has been triggered, and each trigger interval is less than a wait function, it will be called once the case where the image stabilization, and the case where the throttle function is called at regular intervals (parameter wait).

Shake

Simple shake


function debounce(fn, wait) {
    // 缓存定时器
    var timer = null;    
    return function(...args) {
        if (timer) clearTimeout(timer)
            timer = setTimeout(() => {
            fn.apply(this, args)
        }, wait)
    }
}

// 处理函数
function handle() {    
    console.log('测试防抖'); 
}

// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));

The above image stabilization function does not execute the event immediately,

With anti-shake function to achieve immediate execution


/**
 * 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
 *
 * @param  {function} func        回调函数
 * @param  {number}   wait        表示时间窗口的间隔
 * @param  {boolean}  immediate   设置为ture时,是否立即调用函数
 * @return {function}             返回客户调用函数
 */
function debounce (func, wait = 50, immediate = true) {
  let timer, context, args;

  // 延迟执行函数
  const later = () => setTimeout(() => {
      timer = null;
    // 延迟执行的情况下,函数会在延迟函数中执行
    // 使用到之前缓存的参数和上下文
    if (!immediate) {
        func.apply(context, args)
        context = args = null
    }
   
  },wait)

   return function(...params) {
    // 如果没有创建延迟执行函数(later),就创建一个
    if (!timer) {
      timer = later()
      // 如果是立即执行,调用函数
      // 否则缓存参数和调用上下文
      if (immediate) {
        func.apply(this, params)
      } else {
        context = this
        args = params
      }
    // 如果已有延迟执行函数(later),调用的时候清除原来的并重新设定一个
    // 这样做延迟函数会重新计时
    } else {
      clearTimeout(timer)
      timer = later()
    }
  }
}

Throttling

Anti-shake and the throttle is essentially not the same. Anti-shake is executed multiple times becomes the last execution, the throttle is repeatedly executed every so often become.

Throttling


/**
 * underscore 节流函数,返回函数连续调用时,func 执行频率限定为 次 / wait
 *
 * @param  {function}   func      回调函数
 * @param  {number}     wait      表示时间窗口的间隔
 * @param  {object}     options   如果想忽略开始函数的的调用,传入{leading: false}。
 *                                如果想忽略结尾函数的调用,传入{trailing: false}
 *                                两者不能共存,否则函数不能执行
 * @return {function}             返回客户调用函数
 */
_.throttle = function(func, wait, options) {
    var context, args, result;
    var timeout = null;
    // 之前的时间戳
    var previous = 0;
    // 如果 options 没传则设为空对象
    if (!options) options = {};
    // 定时器回调函数
    var later = function() {
      // 如果设置了 leading,就将 previous 设为 0
      // 用于下面函数的第一个 if 判断
      previous = options.leading === false ? 0 : _.now();
      // 置空一是为了防止内存泄漏,二是为了下面的定时器判断
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    };
    return function() {
      // 获得当前时间戳
      var now = _.now();
      // 首次进入前者肯定为 true
      // 如果需要第一次不执行函数
      // 就将上次时间戳设为当前的
      // 这样在接下来计算 remaining 的值时会大于0
      if (!previous && options.leading === false) previous = now;
      // 计算剩余时间
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      // 如果当前调用已经大于上次调用时间 + wait
      // 或者用户手动调了时间
      // 如果设置了 trailing,只会进入这个条件
      // 如果没有设置 leading,那么第一次会进入这个条件
      // 还有一点,你可能会觉得开启了定时器那么应该不会进入这个 if 条件了
      // 其实还是会进入的,因为定时器的延时
      // 并不是准确的时间,很可能你设置了2秒
      // 但是他需要2.2秒才触发,这时候就会进入这个条件
      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) {
        // 判断是否设置了定时器和 trailing
        // 没有的话就开启一个定时器
        // 并且不能不能同时设置 leading 和 trailing
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

Herein primarily with reference to: the front end of the interview track

Guess you like

Origin www.cnblogs.com/shengmo/p/11423435.html