This article was originally published at: github.com/bigo-fronte… Welcome to follow and reprint.
Js function anti – shake and throttling
If the throttle
concept
-
Debounce: Combines events that trigger very frequently, such as keystrokes, into one execution.
-
Throttle: Perform a constant number of times per X milliseconds, such as every 200ms to check the scroll position and trigger the CSS animation.
-
RequestAnimationFrame: An alternative to throttle, used when functions need to recalculate and render elements on the screen to ensure smooth animation or changes. Note: IE9 does not support this.
The significant difference between anti-shake and throttling is that throttling performs only one task in a specified interval, while anti-shake performs only one task when the interval between tasks exceeds a certain threshold.
debounce
The debounce function means that no matter how many callbacks are triggered within a given period of time, a function is executed only once, meaning that frequent events are triggered and combined into one execution (such as keyboard input).
The implementation principle is to use timers. When the function is executed for the first time, a timer is set, and when it is called, the previous timer will be cleared and a new timer will be reset. If there is a timer that has not been cleared, the function will be triggered when the timer ends.
cosnt debounce = function(func, wait, immediate) {
let timer = null;
// After the timer finishes
// 1. Clear the timer so that it does not affect the triggering of the next consecutive event
// execute func
let later = function(context, args) {
timer = null;
return func.apply(context, args);
}
let handler = function(. args) {
const context = this;
if (timer) {
clearTimeout(timer);
}
let result;
// If immediate is true, the function is executed immediately for the first time without waiting
// Whether the timer is null can determine whether it is the first time to trigger
if (immediate) {
letshouldCall = ! timer; timer =setTimeout(later.bind(null, context, args), wait);
if(shouldCall) { result = func.apply(context, args); }}else {
timer = setTimeout(later.bind(null, context, args), wait);
}
return;
}
return handler;
}
// DEMO1
// Execute debounce to return the new function
const betterFn = debounce(() = > console.log('FN anti-shake performed'), 1000)
// Stop sliding for 1 second and execute function () => console.log(' FN anti-shake executed ')
document.addEventListener('scroll', betterFn)
// DEMO2
// Execute debounce to return the new function
const betterFn = debounce(() = > console.log('FN anti-shake performed'), 1000.true)
// Immediately execute function () => console.log('fn anti-shake executed ')
// Stop sliding for 1 second and execute function () again => console.log(' FN anti-shake executed ')
document.addEventListener('scroll', betterFn)
Copy the code
throttle
Ensure a constant number of executions per X ms, such as one page scroll every 200ms
There are two implementation schemes:
- Have the first one is judged by timestamp to the execution time, record the last execution time stamp, and then every time the triggering event callback, the callback is to judge the current timestamp from the last execution time stamp is the interval of reaching time difference (Xms), if is executed, the last time and update the timestamp of execution, so cycle.
function throttle(func, threshold = 200) {
// The last time fn was executed
let previous = 0;
return function(. args) {
// Get the current time
let now = +new Date(a);// Compare the current time to the last time the function was executed
// Set previous to the current time and execute fn if the wait time is greater than that
if (now - previous > threshold) {
previous = now;
func.apply(this, args); }}}Copy the code
- The second way is to use timers, such as when
scroll
Print one as soon as the event is triggeredhello worldAnd then set a1000ms
The timer is triggered each time thereafterscroll
Event triggers a callback, and if a timer already exists, the callback does not execute the method until the timer fires,handler
Cleared, and then reset the timer.
Function throttle(func, threshold = 200) {function throttle(func, threshold = 200) { return function(... Args) {// Return if (timer) return if the timer exists; Timer = setTimeout(() => {// Execute the function and set the timer to null timer = null; func.apply(this, args); }, threshold); }}Copy the code
We’ll look at the response time of the above two kinds of timer, the first timer is executed immediately, the second timer is need to wait for threshold before execution, that whether we can implement a can be executed immediately, can also be performed again after waiting for threshold function, can also be performed immediately and to perform a function at the end?
Combining the above two methods, we add leading and trailing parameters to judge
- Configure whether to respond to the initial callback of the event (
leading
Parameters,false
Ignore) - Configure whether to respond to the callback after the event (
trailing
Parameters,false
Ignore)
const throttle = function(func, wait, options) {
var timeout, context, args, result;
// The last time the callback was executed
var previous = 0;
// If no arguments are passed in, initialize options as an empty object
if(! options) options = {};var later = function() {
// set {leading: false}
// Set previous to 0 each time the callback is triggered
// Otherwise, the current time
previous = options.leading === false ? 0 : _.now();
// To prevent memory leaks, set it to null for later reference! Timeout Sets a new timeout
timeout = null;
// Execute the function
result = func.apply(context, args);
if(! timeout) context = args =null;
};
// This function is executed each time the event callback is triggered
// check whether func is executed within the function
// func is the function our business layer code wants to execute
var throttled = function() {
// Record the current time
var now = _.now();
// The first time the previous timestamp is 0
// set {leading: false} (leading: false)
// Set previous to the current value
if(! previous && options.leading ===false) previous = now;
// The time to wait until the next func trigger
var remaining = wait - (now - previous);
context = this;
args = arguments;
// Remaining <= 0 or remaining <= 0
{leading: false} is not passed, and the first callback is triggered immediately
// Wait - (now - previous) <= 0
// The previous value is then quickly set to now
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
// clearTimeout(timeout) does not set timeout to null
// Set it manually for subsequent judgment
timeout = null;
}
// Sets previous to the current time
previous = now;
// Execute the func function
result = func.apply(context, args);
if(! timeout) context = args =null;
} else if(! timeout && options.trailing ! = =false) {
// The last time you need to trigger
// If a timer already exists, the if branch will not be entered
// If {trailing: false} is the last time that it does not need to trigger, it will not enter the branch
// The later method is triggered after remaining milliseconds
timeout = setTimeout(later, remaining);
}
return result;
};
return throttled;
};
// DEMO
// Execute throttle to return the new function
const betterFn = throttle(() = > console.log('Fn function executed'), 1000)
BetterFn is executed every 10 milliseconds, but only if the time difference is greater than 1000
setInterval(betterFn, 10)
Copy the code
requestAnimationFrame
Instead of throttle, it can be used when functions need to recalculate and render elements on the screen to ensure smooth animation or changes. Note: IE9 does not support this.
let start = null;
const element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';
const step = function(timestamp) {
if(! start) start = timestamp;let progress = timestamp - start;
element.style.left = Math.min(progress / 10.200) + 'px';
if (progress < 2000) {
window.requestAnimationFrame(step); }}window.requestAnimationFrame(step);
Copy the code
Welcome everyone to leave a message to discuss, wish smooth work, happy life!
I’m bigO front. See you next time.