_.debounce是做什么的?
我一直在研究的项目使用_.debounce()。
Underscore JS的反弹文档如下:
_.debounce(function, wait, [immediate])
创build并返回传递的函数的新的去抖动版本,该函数将延迟执行,直到自上次调用以来经过了等待毫秒。
这显然假定任何人想知道什么是反弹的手段,已经知道什么是反弹手段。
什么是反弹实际上呢?
基本上它会限制呼叫,所以如果在短时间内多次呼叫,只会调用一个实例。
你为什么要用它?
像window.onresize事件快速连续发生多次。 如果您需要在新职位上进行大量计算,则不需要多次执行计算。 您只想在用户完成resize事件时触发它。
来自underscore.js 源代码的描述:
返回一个函数,只要它继续被调用,就不会被触发。 该函数停止被调用N毫秒后将被调用。 如果“立即”通过,触发function的前沿,而不是尾随。
自我编码:
_.debounce = function(func, wait, immediate) { var timeout, result; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) result = func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) result = func.apply(context, args); return result; }; };
我写了一篇标题为“ Demistifying Debounce in JavaScript ”的文章,其中我详细解释了debounce 函数是如何工作的,并包含演示。
去抖动function提供了一种“调节”function执行的方法。 它们通常用于function受限于快速连续发生的事件的情况。 在窗口大小和滚动上使用去抖function是很常见的。
无论是下划线还是另一个JavaScript库,所有去抖动函数都是基于JavaScript的本地setTimeout
方法构build的。 因此,在深入了解防抖function的作用之前,最好对WindowTimers
有一个全面的了解 (链接到MDN)。
另外,你需要对范围和闭包有一个很好的理解。 虽然尺寸相对较小,但是去抖动function实际上使用了一些非常先进的JavaScript概念!
这就是说,下面是我在上面引用的post中解释和演示的基本的去抖function。
成品
// Create JD Object // ---------------- var JD = {}; // Debounce Method // --------------- JD.debounce = function(func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if ( !immediate ) { func.apply(context, args); } }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait || 200); if ( callNow ) { func.apply(context, args); } }; };
说明
// Create JD Object // ---------------- /* It's a good idea to attach helper methods like `debounce` to your own custom object. That way, you don't pollute the global space by attaching methods to the `window` object and potentially run in to conflicts. */ var JD = {}; // Debounce Method // --------------- /* Return 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 `wait` milliseconds. If `immediate` is passed, trigger the function on the leading edge, instead of the trailing. */ JD.debounce = function(func, wait, immediate) { /* Declare a variable named `timeout` variable that we will later use to store the *timeout ID returned by the `setTimeout` function. *When setTimeout is called, it retuns a numeric ID. This unique ID can be used in conjunction with JavaScript's `clearTimeout` method to prevent the code passed in the first argument of the `setTimout` function from being called. Note, this prevention will only occur if `clearTimeout` is called before the specified number of milliseconds passed in the second argument of setTimeout have been met. */ var timeout; /* Return an anomymous function that has access to the `func` argument of our `debounce` method through the process of closure. */ return function() { /* 1) Assign `this` to a variable named `context` so that the `func` argument passed to our `debounce` method can be called in the proper context. 2) Assign all *arugments passed in the `func` argument of our `debounce` method to a variable named `args`. *JavaScript natively makes all arguments passed to a function accessible inside of the function in an array-like variable named `arguments`. Assinging `arguments` to `args` combines all arguments passed in the `func` argument of our `debounce` method in a single variable. */ var context = this, /* 1 */ args = arguments; /* 2 */ /* Assign an anonymous function to a variable named `later`. This function will be passed in the first argument of the `setTimeout` function below. */ var later = function() { /* When the `later` function is called, remove the numeric ID that was assigned to it by the `setTimeout` function. Note, by the time the `later` function is called, the `setTimeout` function will have returned a numeric ID to the `timeout` variable. That numeric ID is removed by assiging `null` to `timeout`. */ timeout = null; /* If the boolean value passed in the `immediate` argument of our `debouce` method is falsy, then invoke the function passed in the `func` argument of our `debouce` method using JavaScript's *`apply` method. *The `apply` method allows you to call a function in an explicit context. The first argument defines what `this` should be. The second argument is passed as an array containing all the arguments that should be passed to `func` when it is called. Previously, we assigned `this` to the `context` variable, and we assigned all arguments passed in `func` to the `args` variable. */ if ( !immediate ) { func.apply(context, args); } }; /* If the value passed in the `immediate` argument of our `debounce` method is truthy and the value assigned to `timeout` is falsy, then assign `true` to the `callNow` variable. Otherwise, assign `false` to the `callNow` variable. */ var callNow = immediate && !timeout; /* As long as the event that our `debounce` method is bound to is still firing within the `wait` period, remove the numerical ID (returned to the `timeout` vaiable by `setTimeout`) from JavaScript's execution queue. This prevents the function passed in the `setTimeout` function from being invoked. Remember, the `debounce` method is intended for use on events that rapidly fire, ie: a window resize or scroll. The *first* time the event fires, the `timeout` variable has been declared, but no value has been assigned to it - it is `undefined`. Therefore, nothing is removed from JavaScript's execution queue because nothing has been placed in the queue - there is nothing to clear. Below, the `timeout` variable is assigned the numerical ID returned by the `setTimeout` function. So long as *subsequent* events are fired before the `wait` is met, `timeout` will be cleared, resulting in the function passed in the `setTimeout` function being removed from the execution queue. As soon as the `wait` is met, the function passed in the `setTimeout` function will execute. */ clearTimeout(timeout); /* Assign a `setTimout` function to the `timeout` variable we previously declared. Pass the function assigned to the `later` variable to the `setTimeout` function, along with the numerical value assigned to the `wait` argument in our `debounce` method. If no value is passed to the `wait` argument in our `debounce` method, pass a value of 200 milliseconds to the `setTimeout` function. */ timeout = setTimeout(later, wait || 200); /* Typically, you want the function passed in the `func` argument of our `debounce` method to execute once *after* the `wait` period has been met for the event that our `debounce` method is bound to (the trailing side). However, if you want the function to execute once *before* the event has finished (on the leading side), you can pass `true` in the `immediate` argument of our `debounce` method. If `true` is passed in the `immediate` argument of our `debounce` method, the value assigned to the `callNow` variable declared above will be `true` only after the *first* time the event that our `debounce` method is bound to has fired. After the first time the event is fired, the `timeout` variable will contain a falsey value. Therfore, the result of the expression that gets assigned to the `callNow` variable is `true` and the function passed in the `func` argument of our `debounce` method is exected in the line of code below. Every subsequent time the event that our `debounce` method is bound to fires within the `wait` period, the `timeout` variable holds the numerical ID returned from the `setTimout` function assigned to it when the previous event was fired, and the `debounce` method was executed. This means that for all subsequent events within the `wait` period, the `timeout` variable holds a truthy value, and the result of the expression that gets assigned to the `callNow` variable is `false`. Therefore, the function passed in the `func` argument of our `debounce` method will not be executed. Lastly, when the `wait` period is met and the `later` function that is passed in the `setTimeout` function executes, the result is that it just assigns `null` to the `timeout` variable. The `func` argument passed in our `debounce` method will not be executed because the `if` condition inside the `later` function fails. */ if ( callNow ) { func.apply(context, args); } }; };
它持有一个函数的执行,直到超时过期。 这是为了避免在不需要时继续执行function。 注意,因为underscore.debounce()依赖于复杂的代码。 大多数时候,函数内部的一个简单的“if”语句要比去抖动要快得多。 你可以实现一个计数器,每执行一次迭代N次,或者超时,检查至less经过了一定数量的毫秒。