preface
Frequent event triggers are encountered in front-end development, such as:
- Window resize, scroll
- Mousedown, mousemove
- 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:
- Debounce stabilization
- 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:
- This points to the
- The event object
- 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