en.javascript.info
en.javascript.info copied to clipboard
Solution for throttle decorator is incorrect. (Decorators and forwarding, call/apply)
Original code: https://javascript.info/call-apply-decorators#throttle-decorator
Here's a small code snippet to show where it doesn't work.
function f(a) { console.log(a) };
let g = throttle(f, 1000);
for(let i = 0; i < 1e8; i++) g(i);
Expected Output
1, 249204, 452039, ... , 9999999 (These are random increasing numbers)
Output
1, 9999999
Why does it fail?
function wrapper() {
if (isThrottled) { // (2)
savedArgs = arguments;
savedThis = this;
return;
}
isThrottled = true;
func.apply(this, arguments); // (1)
setTimeout(function() {
isThrottled = false; // (3)
if (savedArgs) {
wrapper.apply(savedThis, savedArgs);
savedArgs = savedThis = null;
}
}, ms);
}
In above, isThrottled = false assignment is done inside setTimeout callback. However, only one callback is pushed into task queue and it isn't executed until stack is empty (for loop has to be completed).
isThrottled is always true => setTimeout isn't called => one callback (that was registered for initial false isThrottled) => cb executed at end and outputs last value => output: 1, 9999999.
Correct Solution: https://github.com/javascript-tutorial/en.javascript.info/pull/2844
This PR giving an alternative solution.