Image stabilization

Code implementation

So let’s say that the scenario that I’m going to implement here is a scenario where you hit the login button multiple times and you’re going to send network requests to the back end multiple times and we want to only trigger one last time when the user hits the login button very frequently and that’s when throttling is used

let btn = document.querySelector('.btn');
function debounce(fn, delay){
    let timeout = null;
    return function(){
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            fn()
        }, delay);
    }
}
function show(){
    console.log(1);
}
btn.addEventListener('click', debounce(show, 2000));
Copy the code

So I’ve implemented a simple throttling function here and you can see it’s using a closure so debounce is called directly and returns an anonymous function so there’s a closure there and when I hit it for the first time timeout is empty so clearTimeout doesn’t clear any timers When I click the second time and there is already a timer, the previous first timer will be cleared and reset. If the user clicks frequently (less than 2000 milliseconds), the previous timer will be cleared each time and a new timer will be reset So this fn function isn’t going to be triggered until the user stops clicking (or after 2000 milliseconds) and we can make a network request from here

Existing problems

1 this refers to the problem

In fact, the second argument in the btn.adDeventListener () listener is a function that executes when, for example, the click event is triggered. This of the function refers to this element

btn.addEventListener('click', function(){ console.log(this); <button class=" BTN "> </button>})Copy the code

But in fn, this refers to window

function show(){
    console.log(this)
    // window
    console.log(1);
}
Copy the code

The solution is to change the orientation of this in fn

let btn = document.querySelector('.btn'); function debounce(fn, delay){ let timeout = null; Return function(){clearTimeout(timeout); return function(){clearTimeout(timeout); Timeout = setTimeout(() => {// I'm binding this directly because I'm using the arrow function, so the arrow function this is the context that it defines. delay); } } function show(){ console.log(1); } btn.addEventListener('click', debounce(show, 2000)); Function debounce(fn, delay){let timeout = null; Return function(){const that = this; const that = this; const that = this; clearTimeout(timeout); Timeout = setTimeout(function(){// There is no way to use arrow functions here, so here I'm going to record this of the returned function and then apply a binding to fn.apply(that); }, delay) } } */Copy the code
2 Event object problem

In fact, the second argument in the btn.adDeventListener () listener is a function that’s going to be executed when, for example, a click event is raised in this case and it’s going to have a default argument event event object

btn.addEventListener('click', function(e){ console.log(e) console.log(this); <button class=" BTN "> </button>})Copy the code

You can print it out for yourself it’s an event object and there’s a lot of stuff in it but there’s no event in the fn function that we’re going to execute when we click on it and the event object prints out undefined

function show(e){
    console.log(this);
    // window
    console.log(e);
    // undefined
    console.log(1);
}
Copy the code

The solution is to pass the Event object into the FN function

let btn = document.querySelector('.btn'); function debounce(fn, delay){ let timeout = null; Return function(){return function(){let args = arguments; clearTimeout(timeout); timeout = setTimeout(() => { fn.apply(this, args); }, delay); } } function show(){ console.log(1); } btn.addEventListener('click', debounce(show, 2000));Copy the code

Code implementation – Add a feature

So in this case, we’re going to execute after delay milliseconds so now I’m thinking not only can I execute after delay milliseconds but one thing I can do is I’m going to execute after I click and the last click doesn’t execute and you can do that either way so we can just throttle the function Debounce is also passed a bool to allow you to pass in true/fasle to select the mode you want

let btn = document.querySelector('.btn'); function debounce(fn, delay, bool){ let timeout = null; return function(){ const args = arguments; clearTimeout(timeout); if(bool) { if(! timeout) { fn.apply(this, args); } timeout = setTimeout(() => { timeout = null}, delay); }else { timeout = setTimeout(() => { fn.apply(this, args); }, delay); } } } function show(){ console.log(1); } btn.addEventListener('click', debounce(show, 2000, true));Copy the code

Conclusion: The switch between the two modes is one after a click, when there is a frequent click, it will be executed after the delay milliseconds after the last click; the other is immediately executed after a click, it will not be executed after the frequent click until the last frequent click, and the process will be repeated after the second click after the delay milliseconds You can look at the code and see for yourself

The throttle

Code implementation

I’m not going to write any of the problems that I’ve already solved and I’m just going to write the implementation of the code

Code implementation -1 timestamp way

function throttle(fn, delay, bool){ let previous = 0; return function(){ let now = new Date().valueOf(); if(now - previous > delay){ fn.apply(this, arguments); previous = now; }}}Copy the code

Here, when the user clicks frequently, it will trigger only once within the specified delay time and then repeatedly after the delay

Code to achieve 2- timer way

function throttle(fn, delay, bool){ let timeout = null; return function(){ let args = arguments; if(! timeout){ timeout = setTimeout(() => { timeout = null; fn.apply(this, args); }, delay) } } }Copy the code

Here is when the user clicks frequently will trigger the last time within the specified delay time

The difference between throttling and anti-shake functions

When the user clicks frequently, the anti-shake function will be triggered after the delay time after the user clicks last time, while the throttling function will be triggered within the specified delay time no matter how frequently the user clicks