The image stabilization throttle javascript

Shake

If you encounter a problem in the daily development in the rolling event needs to be a realization of complex calculations or operations against the second click of a button.
These requirements can be achieved through anti-shake function. Especially the first demand, if you do complex calculations in frequent event callback, is likely to lead to a page Caton, as will be counted more than once merged into one calculation, only at a precise point do the operation.
PS: image stabilization and the role of the throttle function is to prevent multiple calls. 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).

Let's look at a pocket-sized version of the anti-shake image stabilization understand how the realization of:

// func是用户传入需要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
  // 缓存一个定时器id
  let timer = 0
  // 这里返回的函数是每次用户实际调用的防抖函数
  // 如果已经设定过定时器了就清空上一次的定时器
  // 开始一个新的定时器,延迟执行用户传入的方法
  return function(...args) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, args)
    }, wait)
  }
}
// 不难看出如果用户调用该函数的间隔小于wait的情况下,上一次的时间还未到就被清除了,并不会执行函数

This is a simple version of the anti-shake, however flawed, the anti-shake only at the last call. Generally there will be immediate option of image stabilization, indicating whether the call immediately. This difference between the two, give it chestnuts:

  • For example, in a search engine search problems, we certainly hope that the user has finished entering the last word before the call to query interface, this time delay applies anti-shake function is executed, it is always called after a series (interval is less than the wait) function triggers.
  • For example the user to interviewMap point star, we hope that the next time the user first point went to call interface, and change the appearance of the star button after successful, the user can immediately get feedback star if successful, this applies anti immediate execution shake function, it is always the first call, and time must be before the first call to the next call will trigger interval is greater than wait.

Let us implement a stabilization function with immediate execution options

// 这个是用来获取当前时间戳的
function now() {
  return +new Date()
}
/**
 * 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 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()
    }
  }
}

The overall function is not difficult to achieve, to sum up.
Click the button for the achievement of the anti-: If the function is executed immediately, call immediately, if the function is to delay the implementation of the cache on the context and parameters into the delay function to perform. Once I started a timer, the timer as long as I still, every time you click I have re-timing. Once you are tired point, the timer expires, the timer is reset to null, you can again click on.
For the realization of the delay is a function of execution: Clear timer ID, if you call the function call is delayed

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.

/**
 * 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;
    };
  };

inherit

In ES5, we can use the following solution to the question of succession


function Super() {}
Super.prototype.getNumber = function() {
  return 1
}

function Sub() {}
let s = new Sub()
Sub.prototype = Object.create(Super.prototype, {
  constructor: {
    value: Sub,
    enumerable: false,
    writable: true,
    configurable: true
  }
})

The idea is to achieve the above prototype inheritance subclass of parent class prototype set
in ES6, we can easily solve this problem by class syntax

class MyDate extends Date {
  test() {
    return this.getTime()
  }
}
let myDate = new MyDate()
myDate.test()

But ES6 is not compatible with all browsers, so we need to use Babel to compile the code.
If you use a compiler nice code calls myDate.test () you will be surprised to find that there has been an error
Uncaught TypeError: this is not a Date object at MyDate getDate ( ) at MyDate test ( : 23: 19) at : 1: 8

Since the underlying limits the instances must be constructed by the Date, then we can change the thinking at inheritance

function MyData() { }
MyData.prototype.test = function () {
  return this.getTime()
}
let d = new Date()



Object.setPrototypeOf(d, MyData.prototype)
Object.setPrototypeOf(MyData.prototype, Date.prototype)

Inherit the implementation of the above ideas: first create the parent class instance => change the original instance _proto__ in turn connected to a prototype subclass => prototype of a subclass of the proto prototype instead of the parent class.

Inherit the implementation by the above method can be the perfect solution to this limitation JS underlying.

Guess you like

Origin www.cnblogs.com/guangzan/p/11274237.html