If a function is called repeatedly in a short period of time, application performance will be affected and resources will be consumed. For example:
- In the input box content change test, automatic trigger interface submission or interface query
- Trigger onClick, onScroll, and onMousemove events multiple times
And so on, this problem may occur.
To deal with this problem, you need to control the number and frequency of function calls, rather than doing one execution for every trigger. At this time, it is necessary to introduce two concepts of function tremble and throttling, and I will introduce them in detail.
First, we use mousemove event to reproduce the scene where the function is frequently called repeatedly. The page code is as follows:
<body>
<div id="box">0</div>
</body>
<script>
var $box = document.getElementById('box');
var runTimes = 0
$box.addEventListener('mousemove', onMouseMoveEvent)
function onMouseMoveEvent() {
runTimes++;
box.innerHTML = runTimes;
}
</script>
Copy the code
Running the code in a browser looks like this:
As you can see in the GIF above, the onMouseMoveEvent function is called hundreds of times as you move the mouse over the area listening for mousemove events.
Accordingly, we abstracted the simulation diagram of the number of times the onMouseMoveEvent function was called within 15s as follows:
- The yellow bar represents a call to the onMouseMoveEvent function
Let’s take a look at how the number and frequency of function calls change after the introduction of anti-shake throttling.
Function debounce
Let’s take a look at the common anti-shake functions
function debounce(func, wait) {
let timeout;
return function () {
const context = this;
const args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() = >{ func.apply(context, args) }, wait); }}Copy the code
From the logic of the code, we can understand the expected effect of function shaking prevention as follows:
- Given a delay time, the function will not be executed immediately if the interval between calls is shorter than this time, but will continue to wait. When the wait time exceeds this set time, the function will be executed.
How does that actually work? Let’s introduce the anti-shake to mousemove
$box.addEventListener('mousemove',debounce(onMouseMoveEvent, 1000))
Copy the code
-
Pass the Mousemove event response function onMouseMoveEvent to the anti-shock function Debounce
-
Wait time set wait to 1000ms
Let’s take a look at the implementation:
As can be seen from the GIF figure, the call times of onMouseMoveEvent function are significantly reduced, and the call times will not change when moving the mouse in the area. After the mouse pauses for 1s, the call times will increase by 1 until the call stops after the mouse stops moving for 1s.
Based on this, we abstractly draw an example diagram of the number of times onMouseMoveEvent is called after the introduction of anti-shake:
Here we can summarize a little bit:
- If the interval between calls is less than the set wait time, the last call is ignored and the last one is not executed until the interval is greater than the wait time.
In fact, there is another version of the anti-shake function immediately executed, the code is as follows:
function debounce(func,wait) {
let timeout;
return function () {
const context = this;
const args = arguments;
if (timeout) clearTimeout(timeout);
constcallNow = ! timeout; timeout =setTimeout(() = > {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}
Copy the code
In fact, the common JavaScript tool library Underscore uses immediate execution as a configuration item, and the following is a similar configurable Underscore function:
/ * * *@desc Function stabilization *@param Func function *@param Number of milliseconds to delay wait execution *@param Immediate true The table is executed immediately. False The table is not executed immediately */
function debounce(func,wait,immediate) {
let timeout;
return function () {
const context = this;
const args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
constcallNow = ! timeout; timeout =setTimeout(() = > {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}}Copy the code
Function throttle
Throttling and anti-shake are both designed to control the number of calls when they are triggered frequently, but the difference is that throttling is expected to flow slowly and the frequency of calls is more regular than that of anti-shake. Let’s take a look at the throttling function below:
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if(! timeout) { timeout =setTimeout(() = > {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
Copy the code
As can be seen from the above implementation code, the throttling function does not reset the customizer through clearTimeout when the function is frequently called. Instead, after the timer is initialized, that is, timeout === true, the timer is guaranteed to complete smoothly, so that the call frequency mentioned above is more regular.
Let’s apply the throttling function to mousemove listener events
$box.addEventListener('mousemove',throttle(onMouseMoveEvent, 1000))
Copy the code
- Pass the Mousemove event response function onMouseMoveEvent to the throttle function
- Wait time set wait to 1000ms
Let’s take a look at the implementation:
As can be seen from the GIF figure, the number of calls to the onMouseMoveEvent function also increases slowly. When the mouse moves in the area, the number of calls increases once every 1s until the mouse stops moving for 1s and the call stops.
Similarly, let’s abstract an example graph of how many times onMouseMoveEvent is called after the throttling function is introduced:
Here we can summarize the throttling function:
- After the function introduces throttling, after the function triggered for the first time starts the timer, all triggers in the waiting time will be ignored until the timer completes the function execution, and the next trigger will start a new timer, and the above process will be repeated.
In addition, there is a timestamp version of the throttling function, but because it does not affect our understanding of the throttling idea, so no extension, interested friends can search by themselves.
References:
Github.com/mqyqingfeng…
Github.com/mqyqingfeng…