1, Know anti shake and throttling
1.1. Understanding of anti shake and throttling
In fact, the concepts of anti chattering and throttling did not first appear in software engineering. Anti chattering appeared in electronic components and throttling appeared in fluid flow
- JavaScript is event driven. A large number of operations will trigger events and add them to the event queue for processing.
- For some frequent event processing will cause performance loss, we can limit the frequent occurrence of events through anti chattering and throttling;
At present, anti shake and throttling functions are two very important functions in the actual development of the front end, and they are also the interview questions often asked in the interview.
However, many front-end developers are a little confused about these two functions:
- Some developers simply can't tell the difference between anti shake and throttling (often asked in interviews);
- Some developers can distinguish, but do not know how to apply;
- Some developers will use some third-party libraries, but they don't know the internal principle and can't write;
The focus of this article is to solve the above problems:
- We should not only distinguish the difference between anti shake and throttling, but also understand which scenarios will be used in practical work;
- And I will take you a little bit to write my own anti shake and throttling function, not only understand the principle, but also learn to write it myself;
1.2. Why is anti shake throttling required
1.2.1. Why is anti shake required
Let me start with an example from life:
For example, one day after class, I said that if you have any questions to ask me, I will wait for a minute.
- If no students ask me questions in one minute, then I will finish class;
- During this period, classmate a came to ask questions and help him answer them. After answering, I will wait another minute to see if other students ask questions;
- If I wait more than 1 minute, I click finish class (to really execute this time)
We have all encountered such a scenario. Enter the content you want to search in a search box:
For example, if you want to search a MacBook:
- When I input m, for better user experience, corresponding associative content usually appears. These associative content is usually saved in the server, so a network request is required;
- When ma is continuously input, the network request is sent again;
- Then the macbook needs to send a total of 7 network requests;
- This greatly reduces the performance of our whole system, whether it is the front-end event processing or the pressure on the server;
But do we need so many network requests?
- No, the correct way is to send the network request under appropriate circumstances;
- For example, if a user quickly inputs a macbook, it will only send a network request;
- For example, if the user enters an M and thinks about it for a while, m should indeed send a network request at this time;
- That is, we should monitor the user to send the network request when there is no time to trigger again within a certain time, such as 500ms;
This is the operation of anti shake:
Only when a function is not triggered again within a certain time can this function be really called;
Let's use a picture to understand its process;
- When an event is triggered, the corresponding function will not be triggered immediately, but will wait for a certain time;
- When events are triggered intensively, the triggering of functions will be frequently delayed;
- Only after waiting for a period of time and no event is triggered can the response function be truly executed;
There are many application scenarios for anti shake: - Frequently input content in the input box, search or submit information;
- Click the button frequently to trigger an event;
- Monitor browser scrolling events and complete some specific operations;
- resize event when the user zooms the browser;
In short, for dense event triggering, we only want to trigger later events, so we can use the anti shake function;
1.2.2. Why throttling
Let me start with an example from life:
- In the case of classes, I start classes at 8 p.m. every day, which is a fixed frequency;
- No matter how many students tell me, teacher, shall we have class early? No, the lecture starts on time at 8 o'clock in the evening;
Many people have played games like airplane Wars (of course, this is just an example. For your understanding, although most front-end programmers do not play games, this example can well explain the throttling function)
In the game of aircraft war, we press the space to fire a bullet:
- Many aircraft wars games have this setting. Even if the press frequency is very fast, the bullet will maintain a certain frequency to launch; (in fact, many arcade games are like this. Ordinary attacks have the highest frequency);
- For example, the bullet can only be fired once a second. Even if the user presses it 10 times in this second, the bullet will be fired at the frequency of one bullet;
- However, the event is triggered 10 times, and the response function is triggered only once;
This is the operation of throttling:
- In a certain time (such as 500ms), a function can only be triggered once;
We still use a picture to show:
Application scenario of throttling:
- Listen for page scrolling events;
- Mouse movement events;
- Users frequently click the button to operate;
- Some designs in the game;
In short, it is still triggered by intensive events, but the process triggered by intensive events will not wait for the last time to call the function, but will be called according to a certain frequency;
2, Realization of anti shake function
2.1. Anti shake case preparation
We delay the implementation of the anti shake function through a search box:
- Listen to the input of input and simulate the network request by printing
<body> <input class="search" type="text"> <script> // 1. Get input box var search = document.querySelector(".search"); // 2. Listen to the input content and send ajax requests // 2.1. Define a listening function var counter = 0; function searchChange() { counter++; console.log("send out"+ counter +"Network request"); } // Bind oninput search.oninput = searchChange </script> </body> 12345678910111213141516171819
The test found that a fast input macbook sent a total of 7 requests, indicating that we need to perform anti shake operation on it
2.2. User defined anti shake function
We need to implement our own anti shake function.
- Note that in the whole implementation process, I try not to use the syntax of ES6;
- Because if we don't handle our code with babel, the syntax above ES6 will have compatibility problems;
- The anti chattering and throttling functions we encapsulated are not universal;
2.2.1. Basic functions of anti shake
The core idea of anti shake function is as follows:
- When a function is triggered, it will not execute immediately, but will be delayed (delaying the execution of the function through a timer)
- If the function is triggered again within the delay time, cancel the last function execution (cancel the timer);
- If the function is not triggered again within the delay time, the function will execute normally (execute the incoming function);
Next, just turn the idea into code:
- Defining the debounce function requires two parameters to be passed in
- Function to be processed fn;
- Delay time;
- The execution of the incoming function fn is delayed by a timer
- If the function is triggered again during this period, clearTimeout cancels the timer;
- If it is not triggered, it can be executed in the callback function of the timer;
function debounce(fn, delay) { var timer = null; return function() { if (timer) clearTimeout(timer); timer = setTimeout(function() { fn(); }, delay); } } 123456789
2.2.2. Optimize parameters and this
We know that parameters will be passed when the oninput event is triggered, and this in the triggered function points to the current element node
- At present, the execution of fn is an independent function call, and this in it is window
- We need to modify it to the corresponding node object, and this in the returned function points to the node object;
- At present, our fn does not pass any parameters during execution. It needs to pass the parameters passed when triggering the event to fn
- The arguments in the function we return are exactly the parameters we need;
Therefore, our code can be optimized as follows:
function debounce(fn, delay) { var timer = null; return function() { if (timer) clearTimeout(timer); // Get this and argument var _this = this; var _arguments = arguments; timer = setTimeout(function() { // During execution, it is used through apply_ this and_ arguments fn.apply(_this, _arguments); }, delay); } } 12345678910111213
Let's print this and event parameters in searchChange:
2.2.3. Optimize cancel function
Sometimes, while waiting for execution, you may need to cancel the previous operation:
- For example, when the user has searched, but has not had time to send the search, he exits the interface;
- When the user exits, the previous operation can be cancelled;
Let's lengthen the delay time here and add a button below:
- Within the delay time, we click the button to cancel the previous function execution;
This time I give the complete code structure:
- HTML code;
- The first script tag encapsulates the debounce function;
- The second script tag is the business logic js code;
<body> <input class="search" type="text"> <button class="cancel-btn">Cancel event</button> <script> function debounce(fn, delay) { var timer = null; var handleFn = function() { if (timer) clearTimeout(timer); // Get this and argument var _this = this; var _arguments = arguments; timer = setTimeout(function() { // During execution, it is used through apply_ this and_ arguments fn.apply(_this, _arguments); }, delay); } // Cancel processing handleFn.cancel = function() { if (timer) clearTimeout(timer); } return handleFn; } </script> <script> // 1. Get input box var search = document.querySelector(".search"); // 2. Listen to the input content and send ajax requests // 2.1. Define a listening function var counter = 0; function searchChange(e) { counter++; console.log("send out"+ counter +"Network request"); console.log(this); console.log(e.target.value); } // Processing searchChange var _searchChange = debounce(searchChange, 3000); // Bind oninput search.oninput = _searchChange; // 3. Cancel event var cancelBtn = document.querySelector(".cancel-btn"); cancelBtn.onclick = function(event) { _searchChange.cancel(); } </script> </body>
3, Implementation of throttling function
Since both anti chattering and throttling functions deal with frequent events, we can use the same case to practice. In addition, the corresponding optimization operations are relatively similar. Therefore, there is no subdivision here. Some codes are written directly in the implementation process.
3.1. User defined anti shake function
3.1.1. Basic functions of throttling
The default implementation idea of throttling function is realized by timestamp:
- We use a last to record the last execution time
- Before each execution, get the current time now: now - last > interval
- Then execute the function and assign now to last
function throttle(fn, interval) { var last = 0; return function() { // this and argument var _this = this; var _arguments = arguments; var now = new Date().getTime(); if (now - last > interval) { fn.apply(_this, _arguments); last = now; } } }
3.1.2. Optimize cancel function
The cancel function is similar to the anti shake function:
function throttle(fn, interval) { var last = 0; var timer = null; var handleFn = function() { // this and argument var _this = this; var _arguments = arguments; var now = new Date().getTime(); if (now - last > interval) { if (timer) { clearTimeout(timer); timer = null; } fn.apply(_this, _arguments); last = now; } else if (timer === null) { // Just for the last time timer = setTimeout(function() { timer = null; fn.apply(_this, _arguments); }, interval); } } handleFn.cancel = function() { clearTimeout(timer); timer = null; } return handleFn; }