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