Within the else block, when there is a `lastRan`, why do you need to check if (Date.now() - lastRan >= delay) before calling the fn? Isn't that repetitive because we are already setting the delay with the new timeout (lastTimerid) with: delay - (Date.now() - lastRan)?
Hey Prashanth, I understand the function's context depends on from where it is being "called" rather than where it is "declared" and this might sound trivial but can you explain with an example why would we require ( or how critical it is to declare ) the line "const context = this" inside the inner function of throttle function with an example and what "this" inside it would point to and what happens if we don't have this line ? and if we were use arrow functions in all places do we still require the line "const context = this" ? .
@@Learnersbucket After going through your blog I learnt that 1. the "this" inside a function call is window / global in non-strict and undefined in strict mode 2. the "this" inside an inner function is window ( non-strict ) / undefined ( strict mode) 3. the "this" inside a method ( a function declared inside an object ) is the object itself 4. the "this" inside a inner function of a method is window / undefined 5. the "this" inside a function extracted/separated from an object is window/undefined 6. the "this" inside an arrow function is always its parent context 7. the "this" inside an arrow function when declared at the top is window/ global 8. the "this" context can be changed by using .bind, .call, .apply 9. the bound function's context cannot be changed by rebounding / call / apply but can be changed by new ( function constructor invocation ) 10. arrow's function this is static and cannot be changed even by bind/call/appy and throws Typeerror ( TypeError: is not a constructor ) when invoked with "new" keyword Finally the function's context depends on various factors like, whether we are calling function: 1. directly / as a method 2. by bind/apply/call 3. with new key word ( Function constructor ) invocation 4. is an arrow function the line "const context = this" inside the inner function of throttle implemenation makes sense when we attach the throttle as an event handler and we want to execute event handler in the context of "input" so that the "this" inside the inner function of throttle would point to "input" elment's context rather than window/global or even undefined in strict case.
Hi Prashanth, Do you see any problem with below approach, const throttleWithLeadingTime = (fn, delayInMs) => { let timer = null; return function (...args) { if (timer === null) { // when invoked for first time fn.call(this, ...args); timer = Date.now() + delayInMs; } else if (Date.now() > timer) { fn.call(this, ...args); timer = Date.now() + delayInMs; } }; }; const throttleWithTrailingTime = (fn, delayInMs) => { let timer = null; return function (...args) { if (timer === null) { // when invoked for first time timer = Date.now() + delayInMs; } else if (Date.now() > timer) { fn.call(this, ...args); timer = Date.now() + delayInMs; } }; };
i created the below method seems to work fine for me, can u spot any loop holes in the below implementation? const throttler = (arr, limit, callback, delay) => { let flag = true; let queue = [...arr]; return function () { if (flag) { const tasks = queue.splice(0, limit); callback(tasks); flag = false; setTimeout(() => { flag = true; }, delay); } }; }; const newBtn = document.getElementById("btn"); newBtn.addEventListener( "click", throttler( [1, 2, 3, 4, 5, 6, 7, 8], 2, (tasks) => { console.log(tasks); }, 2000 ) );
function throttle(cb, delay = 250) { let shouldWait = false return (...args) => { if (shouldWait) return cb(...args) shouldWait = true setTimeout(() => { shouldWait = false }, delay) } } Will this work as throttle by time function ?
Imagine you clicked twice, function will be executed only once. But in case of Prashant's implementation , function will be executed twice with the delay specified. I think there's a mis-match in how we understand throttling :)
*Last one is way Complex* !
Within the else block, when there is a `lastRan`, why do you need to check if (Date.now() - lastRan >= delay) before calling the fn? Isn't that repetitive because we are already setting the delay with the new timeout (lastTimerid) with: delay - (Date.now() - lastRan)?
Hey Prashanth, I understand the function's context depends on from where it is being "called" rather than where it is "declared" and this might sound trivial but can you explain with an example why would we require ( or how critical it is to declare ) the line "const context = this" inside the inner function of throttle function with an example and what "this" inside it would point to and what happens if we don't have this line ? and if we were use arrow functions in all places do we still require the line "const context = this" ? .
Read this article to understand function and this learnersbucket.com/tutorials/es6/function-this-in-javascript/
@@Learnersbucket After going through your blog I learnt that
1. the "this" inside a function call is window / global in non-strict and undefined in strict mode
2. the "this" inside an inner function is window ( non-strict ) / undefined ( strict mode)
3. the "this" inside a method ( a function declared inside an object ) is the object itself
4. the "this" inside a inner function of a method is window / undefined
5. the "this" inside a function extracted/separated from an object is window/undefined
6. the "this" inside an arrow function is always its parent context
7. the "this" inside an arrow function when declared at the top is window/ global
8. the "this" context can be changed by using .bind, .call, .apply
9. the bound function's context cannot be changed by rebounding / call / apply but can be changed by new ( function constructor invocation )
10. arrow's function this is static and cannot be changed even by bind/call/appy and throws Typeerror ( TypeError: is not a constructor ) when invoked with "new" keyword
Finally the function's context depends on various factors like, whether we are calling function:
1. directly / as a method
2. by bind/apply/call
3. with new key word ( Function constructor ) invocation
4. is an arrow function
the line "const context = this" inside the inner function of throttle implemenation makes sense when we attach the throttle as an event handler and we want to execute event handler in the context of "input" so that the "this" inside the inner function of throttle would point to "input" elment's context rather than window/global or even undefined in strict case.
Correct me if any mistake, this version of mine looks simpler to understand to mwe
function throttle(fn, delay) {
let lastRun = 0;
let timerId = null;
return (...args) => {
const now = Date.now();
if (now - lastRun >= delay) {
fn.apply(this, args);
lastRun = now;
} else {
clearTimeout(timerId);
timerId = setTimeout(() => {
fn.apply(this, args);
lastRun = now;
}, delay);
}
};
}
this will become debouncing i guess
Hi Prashanth, Do you see any problem with below approach,
const throttleWithLeadingTime = (fn, delayInMs) => {
let timer = null;
return function (...args) {
if (timer === null) { // when invoked for first time
fn.call(this, ...args);
timer = Date.now() + delayInMs;
} else if (Date.now() > timer) {
fn.call(this, ...args);
timer = Date.now() + delayInMs;
}
};
};
const throttleWithTrailingTime = (fn, delayInMs) => {
let timer = null;
return function (...args) {
if (timer === null) { // when invoked for first time
timer = Date.now() + delayInMs;
} else if (Date.now() > timer) {
fn.call(this, ...args);
timer = Date.now() + delayInMs;
}
};
};
How do you cancel previous invoked function, if that happens before the delay?
If it is invoked before the delay, it will not go inside IF/ELSE condition, so nothing will happen
Pls correct me, if I'm wrong😊
i created the below method seems to work fine for me, can u spot any loop holes in the below implementation?
const throttler = (arr, limit, callback, delay) => {
let flag = true;
let queue = [...arr];
return function () {
if (flag) {
const tasks = queue.splice(0, limit);
callback(tasks);
flag = false;
setTimeout(() => {
flag = true;
}, delay);
}
};
};
const newBtn = document.getElementById("btn");
newBtn.addEventListener(
"click",
throttler(
[1, 2, 3, 4, 5, 6, 7, 8],
2,
(tasks) => {
console.log(tasks);
},
2000
)
);
can u comment something?
function throttle(cb, delay = 250) {
let shouldWait = false
return (...args) => {
if (shouldWait) return
cb(...args)
shouldWait = true
setTimeout(() => {
shouldWait = false
}, delay)
}
}
Will this work as throttle by time function ?
Nope
How come?@@Learnersbucket
@@whd793 try to run this, there will be mismatch in running consecutive throttles
Imagine you clicked twice, function will be executed only once. But in case of Prashant's implementation , function will be executed twice with the delay specified. I think there's a mis-match in how we understand throttling :)
Is this correct ?
For Leading ->
const leadingThrottle = function (fn , delay) {
let prevR ;
let timer ;
return function(...args){
if(!prevR){
fn.apply(this , args);
timer = Date.now();
prevR = true;
}
else{
if(Date.now() - timer >= delay){
fn.apply(this,args);
timer = Date.now();
}
}
}
}
For Trailing ->
const trailingThrottle = function(fn, delay) {
let lastTimerid;
let lastRan = Date.now();
return function (...args) {
const context = this;
clearTimeout (lastTimerid);
lastTimerid = setTimeout(() => {
if (Date.now() - lastRan >= delay) {
fn.apply (context, args);
lastRan = Date.now() ;
}
}, delay - (Date.now() - lastRan));
}
}
Please run the code and test