Anti chattering throttling function
Anti shake function
- The callback function is executed at the specified time when the last event is triggered
- After triggering the high-frequency event, the function will be executed only once in n seconds. If the high-frequency event is triggered again in n seconds, the time will be recalculated
Click event anti shake
Click multiple times and only execute the last triggered event. Using the characteristics of closures, return is a function in the debounce function.
<script> let btn = document.querySelector('#btn') function debounce(fn, num) { let timeOutId = null return function () { clearTimeout(timeOutId) timeOutId = setTimeout(() => { fn.apply(this, arguments) }, num) } } function clickFun(e) { console.log(2222,e); } btn.addEventListener('click', debounce(clickFun, 1000)) </script>
Listen for page scrolling events
apply accepts that the first parameter is a dropped object, and the second parameter is an array.
function debounce(cb, delay, ...args) { let timer = null return function (e) { if (timer) clearTimeout(timer) timer = setTimeout(() => { cb.apply(this, [e, ...args]) }, delay) } } function windowScroll(e, otherParam) { console.log('Page scrolling', e, otherParam); } // Add page scroll event window.onscroll = debounce(windowScroll, 500, 'otherParam')
Throttling function
- When a high-frequency event is triggered, it is only executed once in n seconds, so throttling will dilute the execution frequency of the function
- Each time an event is triggered, judge whether there is a delay function waiting to be executed
Listen for page scrolling events
Declare a canRun judgment, but there is a delayed execution method. If there is, return. If not, use setTimeout to add a delayed execution callback function
function throttle(cb, delay, ...args) { let canRun = true return function (e) { if (!canRun) return canRun = false setTimeout(() => { cb.apply(this, [e, args]) canRun = true }, delay) } } function windowScroll(e, otherParam) { console.log('Page scrolling', e, otherParam); } window.onscroll = throttle(windowScroll, 1000, 'otherParam')
One trick is not to declare more than one canRun variable. Use an id returned by setTimeout to assign the id to the timer to judge whether the timer is executed
function windowScroll(e, otherParam) { console.log('Page scrolling', e, otherParam); } function throttle(cb, delay, ...args) { let timer = null return (e) => { if (!timer) { timer = setTimeout(() => { // Pass this and Event parameters to the callback cb.apply(this, [e, ...args]) clearTimeout(timer) timer = null }, delay) } } } window.onscroll = throttle(windowScroll, 1000, 'otherParam')
Anti chattering throttling function in Lodash
Lodash: https://www.lodashjs.com/docs/lodash.debounce#_debouncefunc-wait0-options
func (Function): the function to prevent jitter.
[wait=0] (number): the number of milliseconds to delay.
[options=] (Object): option object.
[options.leading=false] (boolean): Specifies the call before the start of the delay.
[options.maxWait] (number): sets the maximum value that func is allowed to delay.
[options.trailing=true] (boolean): Specifies the call after the end of the delay.
Realization of anti shake function
File implementation path: node_modules\lodash\debounce.js
function debounce(func, wait, options) { var lastArgs, // Parameters passed by the calling function lastThis, // this of the calling function maxWait, // Maximum waiting time result, // Execution result of the anti shake function timerId, // id of setTimeout lastCallTime, // Last call time lastInvokeTime = 0, // Last call time leading = false, maxing = false, trailing = true; // func determines whether it is a function if (typeof func != 'function') // Change wait to Number type // If it is an object, the content of the object is assigned to the private attribute leading = !!options.leading; trailing = 'trailing' in options ? !!options.trailing : false; // Save current time var time = now(), // shouldInvoke method to judge whether the callback function should be executed 1, Should be called the first time lastCallTime === undefined 2, 1st + n On the first call a: The delay time has elapsed. You should call: time - lastCallTime >= wait b: In the source code, it is called when the current time is smaller than the last call time, but is this common: time - lastCallTime < 0 c: If there is a maximum delay time, the difference between the current time and the last call time shall be greater than the maximum delay time: (maxing && time - lastInvokeTime >= maxWait)) // Cache the current this and arguments lastArgs = arguments; lastThis = this; // The last execution time is assigned as the current time lastCallTime = time; // Call function if(shouldInvoke method) // After calling the function result = func.apply(thisArg, args); // Reset this and arguments lastArgs = lastThis = undefined; // Return structure return result }
Realization of throttling function
File implementation path: node_modules\lodash\throttle.js
This is all the code of lodash's throttling function. I was confused when I saw the implementation source code of lodash. Can I think debounce is no different from throttle?
import { debounce } './debounce' function throttle(func, wait, options) { var leading = true, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } if (isObject(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } return debounce(func, wait, { 'leading': leading, 'maxWait': wait, 'trailing': trailing }); }
Difference between anti shake and throttling
You can analyze the statement of the anti chattering throttling function in lodash
debounced lodash
Create a debounced (anti shake) function, which will be called wait after delay of wait milliseconds after the last call. Debounced provides an options object that determines how to call the func method, options Leading and | or options Trailing decides how to trigger before and after the delay (Note: first call, wait or wait first, then call).
When func is called, the last parameter supplied to the debounced function is passed in. The debounced function of subsequent calls returns the result of the last func call
**Summary: * * within a certain period of time, the result obtained is the execution result of the last callback call
throttle lodash
Create a throttling function that executes func at most once in a wait second. This function provides a cancel method to cancel the delayed function call and an immediate call to the flush method. You can provide an options object to determine how to call the func method, options Leading and | or options Trailing determines how to trigger before and after the wait. Func will pass in the last parameter to this function.
The function returned is the result of the last func call.
**Summary: * * within a certain period of time, the result obtained is the execution result of the last callback call
Now I have a big question mark??????????
From lodash's documentation and code, it seems that there is no difference between the release
I began to think about the following two codes carefully, and finally I found a different place,
-
Callback function called
debounce if it keeps triggering, the callback function will not be executed, and the last one will be cleared next time (the last one is emphasized)
If the throttle is triggered all the time, it will only put the callback function for the first time into the personal leave queue (the first time is emphasized)
-
Effect of call
debounce if it keeps triggering, the callback function will not execute
If the throttle is triggered all the time, it will be triggered every delay milliseconds
-
Same place
- All are implemented through setTimeout
- It should be executed after delay milliseconds
function debounce(cb, delay, ...args) { let timer = null return function (e) { if (timer) clearTimeout(timer) timer = setTimeout(() => { cb.apply(this, [e, ...args]) }, delay) } }
function throttle(cb, delay, ...args) { let timer = null return (e) => { if (!timer) { timer = setTimeout(() => { // Pass this and Event parameters to the callback cb.apply(this, [e, ...args]) clearTimeout(timer) timer = null }, delay) } } }