preface

Frequent event triggers are encountered in front-end development, such as:

  1. Window resize, scroll
  2. Mousedown, mousemove
  3. Keyup, keydown…

To do this, let’s use sample code to see how events can be fired frequently:

Let’s write an index.html file:

<! DOCTYPE html> <html lang="zh-cmn-Hans"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1"> <title>debounce</title> <style> #container{ width: 100%; height: 200px; line-height: 200px; text-align: center; color: #fff; background-color: #444; font-size: 30px; } </style> </head> <body> <div id="container"></div> <script src="debounce.js"></script> </body> </html>Copy the code

The code for the debelas.js file is as follows:

var count = 1;
var container = document.getElementById('container');

function getUserAction() {
    container.innerHTML = count++;
};


container.onmousemove = getUserAction;Copy the code

Let’s look at the results:

debounce

Sliding from left to right triggers the getUserAction function 165 times!

Because this example is so simple, the browser is fine with it, but what about complex callback functions or Ajax requests? Assuming 60 fires per second, each callback must be completed within 1000/60 = 16.67ms, or there will be a lag.

To solve this problem, there are generally two solutions:

  1. Debounce stabilization
  2. Throttle orifice

Image stabilization

Today focus on the realization of anti – shake.

The principle of image stabilization is: although you trigger event, but I must be executed in event trigger n seconds, if you’re in an event trigger n seconds and triggered this event, then I will be subject to the new event time, n seconds before execution, in short, is to wait for you trigger after n seconds will no longer trigger events, I perform a capricious!

The first edition

From this statement, we can write the first version of the code:

Function debounce(func, wait) {var timeout; return function () { clearTimeout(timeout) timeout = setTimeout(func, wait); }}Copy the code

If we were to use it, take the original example:

container.onmousemove = debounce(getUserAction, 1000);Copy the code

Now you can move it any way you want, but it will not trigger for 1000ms before I execute the event.

It went from 165 to one!

Great. Let’s keep refining it.

this

If we were in the getUserAction function console.log(this), without using debounce, this would have the value:

<div id="container"></div>Copy the code

But if we use our debounce function, this points to the Window object!

So we need to point this to the right object.

Let’s modify the code:

Function debounce(func, wait) {var timeout; return function () { var context = this; clearTimeout(timeout) timeout = setTimeout(function(){ func.apply(context) }, wait); }}Copy the code

Now this is pointing correctly. Let’s move on to the next question:

The event object

JavaScript provides the event object in the event handler. Let’s modify the getUserAction function:

function getUserAction(e) {
    console.log(e);
    container.innerHTML = count++;
};Copy the code

If we don’t use debouce, the MouseEvent object will be printed, as shown:

MouseEvent

But in our implementation of debounce, we just print undefined!

So let’s change the code again:

Function debounce(func, wait) {var timeout; return function () { var context = this; var args = arguments; clearTimeout(timeout) timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}Copy the code

The return value

Note that the getUserAction function may return a value, so we will also return the result of the function’s execution

Function debounce(func, wait) {var timeout, result; return function () { var context = this; var args = arguments; clearTimeout(timeout) timeout = setTimeout(function(){ result = func.apply(context, args) }, wait); return result; }}Copy the code

So far, we’ve fixed three minor issues:

  1. This points to the
  2. The event object
  3. The return value

immediately

At this point, the code is pretty good, but to make this function even better, let’s consider a new requirement.

This requirement is:

I don’t want to wait until the event stops firing. I want to execute the function immediately, and then wait n seconds before I can fire again.

It makes sense to add an immediate parameter to determine whether the request is executed immediately.

Function debounce(func, wait, immediate) {var timeout, result; return function () { var context = this; var args = arguments; if (timeout) clearTimeout(timeout); If (immediate) {var callNow =! timeout; timeout = setTimeout(function(){ timeout = null; }, wait) if (callNow) result = func.apply(context, args) } else { timeout = setTimeout(function(){ result = func.apply(context, args) }, wait); } return result; }}Copy the code

cancel

Finally, let’s think about a small requirement. I want to be able to cancel debounce, say I debounce for 10 seconds with immediate true, so I have to wait 10 seconds before I can trigger the event again. Now I want to have a button that, when clicked, cancels the buffering, So I can trigger again, can execute again immediately, isn’t very happy?

For this requirement, we write the final version of the code:

Function debounce(func, wait, immediate) {var timeout, result; var debounced = function () { var context = this; var args = arguments; if (timeout) clearTimeout(timeout); If (immediate) {var callNow =! timeout; timeout = setTimeout(function(){ timeout = null; }, wait) if (callNow) result = func.apply(context, args) } else { timeout = setTimeout(function(){ result = func.apply(context, args) }, wait); } return result; }; debounced.cancel = function() { clearTimeout(timeout); timeout = null; }; return debounced; }Copy the code

The demo effect is as follows:

debounce-cancel

Now we have fully implemented a underscore function debounce. Congratulations!

series

JavaScript Thematic series directory address: github.com/mqyqingfeng… .

The JavaScript series is expected to write about 20 articles, focusing on the implementation of some function points in daily development, such as anti-shaking, throttling, de-weighting, type judgment, copy, maximum value, flat, Currie, recursion, out-of-order, sorting, etc. (Chao) (XI) underscore and jQuery underscore

If there is any mistake or not precise place, please be sure to give correction, thank you very much. If you like or are inspired by it, welcome star and encourage the author.

Look at the original