What is a chattering function? Underscore we need to understand this concept before we take a look at Underscore functions. A lot of people confuse shaking with throttling, but the two concepts are pretty straightforward.

The Debounce Function is a Function that limits the firing frequency of a given Function. We can think of it as calling the same function many times, and only getting the result of executing the function once; But when you call it again at some point in time, depending on how long you set it up, you can get the new result again. What are the application scenarios of this function?

Let’s say we write a DOM event listener,

window.onscroll = function(){ console.log('Got it! '); }Copy the code

Now when we scroll the mouse wheel, we can see the event being triggered. But we can see that our console keeps printing messages as we roll the mouse wheel, because the Scroll event for the window is constantly triggered by us.

This might be an innocuous behavior in the current scenario, but you can see how our Event handlers can affect computer performance when they involve complex operations such as Ajax requests, DOM rendering, and large amounts of data computation. In some older models or older browsers (IE in particular), this can cause a crash. So we need to find a way to execute event handlers only a certain number of times in a specified period of time.

Understand the shake out function

Some concepts and application scenarios, but still very difficult to say, exactly what is a shake function?

We can understand this through the following example:

Suppose you have the following code:

// The immediate function is not implemented, welcome improvement. var debounce = function (callback, delay, immediate) { var timeout, result; return function () { var callNow; if (timeout) clearTimeout(timeout); callNow = ! timeout && immediate; if (callNow) { result = callback.apply(this, Array.prototype.slice.call(arguments, 0)); timeout = {}; } else { timeout = setTimeout(() => { callback.apply(this, Array.prototype.slice.call(arguments, 0)); }, delay); }}; }; var s = debounce(() => { console.log('yes... '); }, 2000); window.onscroll = s;Copy the code

The debounce function is a simple debounce function that I implemented myself and we can experiment with this code.

The steps are as follows:

  • Copy the code above, open a browser, open the console (F12), paste the code and press Enter to execute.
  • Continuously scroll the mouse to see if the console has output.
  • Stop scrolling and scroll again within 2 seconds to see if there is output.
  • After continuous scrolling, stop for more than 2s to see if there is output.

Through the above steps, we can see that when we continuously scroll the mouse, no message is printed from the console, and when we stop for 2 seconds and scroll again, no message is printed. But when we stop longer than 2s, we can see messages coming out of the console.

This is the shake out function. In consecutive triggers (regardless of duration), you can only trigger once. In the specified time length of continuous trigger, only one trigger effect can be obtained.

The realization of the underscore

The underscore source code is as follows (with code comments) :

// 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. // The trailing function is executed after (or before) the wait time and is executed only once.  // If immediate is passed true, the function is called as soon as it is passed. How it works: With asynchronous JavaScript, multiple calls to the function returned by _. Debounce will execute all at once, but each call will empty the previous TimeoutID, so only the last setTimeout is actually executed. _.debounce = function (func, wait, immediate) { var timeout, result; var later = function (context, args) { timeout = null; // Func is not executed if args is not passed. if (args) result = func.apply(context, args); }; // The function that is returned is called only once. Var debmentioning = restArgs(function (args) {// This line of code will clear the last TimeoutID, so that only the delay of the last call will be executed if the scene of calling this function many times. if (timeout) clearTimeout(timeout); If (immediate) {//// Func is called immediately if immediate is passed and timeout is empty, otherwise not immediately. var callNow = ! timeout; // The func function inside the later function is destined not to be executed because no arguments are passed to later. // Make sure a timeout is returned and wait until milliseconds before executing later. Clearing timeout is the condition that callNow is true if immediate is true. //timeout = setTimeout(later, wait) = setTimeout(later, wait) timeout = setTimeout(later, wait); if (callNow) result = func.apply(this, args); } else {// If immediate is not passed, then the _. Delay function is used to execute later. timeout = _.delay(later, wait, this, args); } return result; }); // This function is used to cancel the current chattering effect. debounced.cancel = function () { clearTimeout(timeout); timeout = null; }; return debounced; };Copy the code

The underscore uses the closure method and defines two private properties, timeout and Result, and two private methods, Later and Debmentioning. Finally, it will return debmentioning as the next function. Timeout is used to accept and store the TimeoutID returned by setTimeout, result is used to execute the result of the func function passed in by the user, and later is used to execute the func function passed in.

Realize the principle of

It takes advantage of JavaScript’s asynchronous execution mechanism. JavaScript executes all synchronous code first and then executes all asynchronous tasks in the event queue.

When we continue to trigger the debmentioning function, it will continue to clearTimeout(timeout) and then reset the new timeout, so in fact, every time we call the debmentioning function will reset the timeout before our synchronization code is finished. Therefore, the asynchronous task in the asynchronous event queue will continue to refresh until the last debmentioning function is finished. Only the asynchronous task of Later set by the last debmentioning function will be executed after the synchronous code is executed.

Therefore, when we continue to scroll the mouse in the previous experiment, in fact, we will continue to call debmentioning function, remove the asynchronous task corresponding to timeout, and then set a new timeout asynchronous task. When we stop for less than 2s, the asynchronous task corresponding to timeout will not be triggered, so scrolling the mouse again and triggering the Debmentioning function will clear the timeout task and then set a new timeout task. Once stopped for more than 2s, the asynchronous code corresponding to the final timeout is executed.

conclusion

  • Chattering is a way to limit the frequency of a function.
  • The function after shaking can be triggered at most once in the specified time. The function after shaking can be triggered continuously only once.
  • The implementation of underscore de-buffering relies on JavaScript’s asynchronous execution mechanism to execute synchronous code first and then asynchronous code in the event queue.

reference

  • An implementation of the underscore function to shake out
  • JavaScript Debounce Function
  • Stack Overflow: What does _. Debounce do?