Throttling and anti-shaking are common in the process of developing projects, such as input input real-time search, scroll lview scroll update, and so on. A large number of scenarios need to be processed. Let's introduce it by Lodash and go straight to the topic.
Lodash
API
-
debounce: multiple triggers, only the last trigger, the execution of the objective function.
lodash.debounce(func, [wait=0], [options={}])
-
throttle: Limit the frequency of target function calls, such as: 2 calls in 1s.
lodash.throttle(func, [wait=0], [options={}])
lodash defines a number of options in the opitons parameter, mainly the following three:
- leading: The function is called at the beginning of each wait delay, with the default value false
- trailing: The function is called at the end of each wait delay, with the default value true
- maxwait: The maximum waiting time, because if debounce's function call time does not meet the conditions, it may never be triggered, so this configuration is added to ensure that a function can be executed once more than a period of time.
According to the combination of learning and trailing, different invocation effects can be achieved:
- {lead: true, trailing: false}: Called only at the beginning of the delay
- {leading: false, trailing: true}: By default, the function will not be called until the end of the delay
- {lead: true, trailing: true}: Called at the beginning of the delay and after the delay ends
deboucne also has a cancel method to cancel jitter-proof calls
Use
-
Deounce:
addEntity = () => { console.log('--------------addEntity---------------') this.debounceFun(); } debounceFun = lodash.debounce(function(e){ console.log('--------------debounceFun---------------'); }, 500,{ leading: true, trailing: false, })
When the first click is executed, click continuously and within 500 ms, no longer execute, click again after 500 ms, execute.
-
throttle:
addEntity = () => { console.log('--------------addEntity---------------'); this.throttleFun(); } throttleFun = lodash.throttle(function(e){ console.log('--------------throttleFun---------------'); }, 500,{ leading: true, trailing: false, })
When the first click is executed, click continuously and within 500 ms, then automatically execute once after 500 ms. (Note: If the number of consecutive clicks is less than 500 ms, it will not execute automatically), then click again after 500 ms.
Source Code Implementation
debounce
// This is used to get the current timestamp function now() { return +new Date() } /** * Anti-jitter function. When the return function is called continuously, the idle time must be greater than or equal to wait before func can execute. * * @param {function} func callback * @param {number} wait Represents the interval between time windows * @param {boolean} immediate Whether to call the function immediately when set to ture * @return {function} Return the client call function */ function debounce (func, wait = 50, immediate = true) { let timer, context, args // Delayed execution function const later = () => setTimeout(() => { // Delay function execution completed, empty the cache timer serial number timer = null // In the case of delayed execution, the function executes in the delayed function // Parameters and contexts used previously cached if (!immediate) { func.apply(context, args) context = args = null } }, wait) // The function returned here is the function actually called each time. return function(...params) { // If no delayed execution function is created, a delayed execution function is created. if (!timer) { timer = later() // If it is executed immediately, call the function // Otherwise, cache parameters and call context if (immediate) { func.apply(this, params) } else { context = this args = params } // If there is a late execution function, clear the original and reset one when calling // Doing so will cause the delay function to recount } else { clearTimeout(timer) timer = later() } } }
throttle
/** * underscore Throttle function. When the return function is called continuously, the execution frequency of func is limited to sub / wait. * * @param {function} func callback * @param {number} wait Represents the interval between time windows * @param {object} options If you want to ignore the call to the start function, pass in {leading: false}. * If you want to ignore the call to the end function, pass in {trailing: false} * They can't coexist, otherwise the function can't be executed. * @return {function} Return the client call function */ _.throttle = function(func, wait, options) { var context, args, result; var timeout = null; // Previous timestamps var previous = 0; // If options are not passed, set it to an empty object if (!options) options = {}; // Timer callback function var later = function() { // If leading is set, set previous to 0 // The first if judgment for the following functions previous = options.leading === false ? 0 : _.now(); // Vacuum one is to prevent memory leaks, the other is for the following timer judgment timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { // Get the current timestamp var now = _.now(); // The first entry must be true // If you need to execute the function for the first time // Set the last timestamp to the current one // This way, the value of remaining will be greater than 0 in the next calculation. if (!previous && options.leading === false) previous = now; // Calculate the remaining time var remaining = wait - (now - previous); context = this; args = arguments; // If the current call is longer than the last call time + wait // Or the user manually schedules the time // If trailing is set, only this condition will be entered. // If leading is not set, this condition will be entered for the first time. // Also, you may feel that if you turn on the timer, you should not enter the if condition. // In fact, it will still enter because of the delay of the timer. // It's not the exact time. You probably set it for 2 seconds. // But it takes 2.2 seconds for him to trigger, and that's when he enters the condition. if (remaining <= 0 || remaining > wait) { // Clean up if a timer exists or call a second callback if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { // Determine whether timers and trailing are set // Turn on a timer if you don't have one. // And you can't set up leading and trailing at the same time. timeout = setTimeout(later, remaining); } return result; }; };
In the end, welcome star: https://github.com/sisterAn/blog
Welcome attention: front-end bottle gentleman