Underscore for JavaScript topics

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:


      
<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:

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

Today focus on the realization of anti – shake.

www.javascriptC.com is a platform dedicated to helping developers change the world with code. You can find the top content in the technology world here every day

Image stabilization

The principle of anti-shake is: you may trigger the event, but I must wait n seconds before the event stops firing.

This means that if you fire an event within n seconds of it firing, THEN I’m going to wait n seconds for the new event to fire.

In short, is to wait for you to trigger the event n seconds no longer trigger the event, I will execute, is really capricious ah!

The first edition

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

/ / the first edition
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 won’t trigger for 1000ms until I execute the event. Take a look at the effect:

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:

/ / the second edition
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:

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

So let’s change the code again:

www.javascriptC.com is a platform dedicated to helping developers change the world with code. You can find the top content in the technology world here every day

/ / the third edition
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

So far, we’ve fixed two minor issues:

  1. This points to the
  2. The event object

immediately

At this point, the code is pretty complete, but to make the function more complete, 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.

/ / the fourth edition
function debounce(func, wait, immediate) {

    var timeout, result;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // If yes, no further action is required
            varcallNow = ! timeout; timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}}Copy the code

Let’s have a look at the effect:

The return value

The getUserAction function may return a value, so we need to return the result of the function’s execution, but when immediate is false, because setTimeout is used, Apply (context, args) returns the value of func.apply(context, args). The value of func.apply(context, args) will always be undefined, so we only return the result of the function if immediate is true.

/ / the fifth edition
function debounce(func, wait, immediate) {

    var timeout, result;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // If yes, no further action is required
            varcallNow = ! timeout; timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
        returnresult; }}Copy the code

www.javascriptC.com is a platform dedicated to helping developers change the world with code. You can find the top content in the technology world here every day

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:

/ / sixth edition
function debounce(func, wait, immediate) {

    var timeout, result;

    var debounced = function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // If yes, no further action is required
            varcallNow = ! timeout; timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
        return result;
    };

    debounced.cancel = function() {
        clearTimeout(timeout);
        timeout = null;
    };

    return debounced;
}
Copy the code

So how do you use this cancel function? Still is the above demo as an example:

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

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

var setUseAction = debounce(getUserAction, 10000.true);

container.onmousemove = setUseAction;

document.getElementById("button").addEventListener('click'.function(){
    setUseAction.cancel();
})
Copy the code

www.javascriptC.com is a platform dedicated to helping developers change the world with code. You can find the top content in the technology world here every day

The demo effect is as follows:

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

Demo code

The code can be found in the Github blog repository

series

JavaScript Thematic series directory address:.

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.

Author: mqyqingfeng Link: github.com/mqyqingfeng…

www.javascriptC.com is a platform dedicated to helping developers change the world with code. You can find the top content in the technology world here every day