How to Debounce a Method Call

How can I debounce a method call?

Put this at the top level of your file so as not to confuse yourself with Swift's funny parameter name rules. Notice that I've deleted the # so that now none of the parameters have names:

func debounce( delay:NSTimeInterval, queue:dispatch_queue_t, action: (()->()) ) -> ()->() {
var lastFireTime:dispatch_time_t = 0
let dispatchDelay = Int64(delay * Double(NSEC_PER_SEC))

return {
lastFireTime = dispatch_time(DISPATCH_TIME_NOW,0)
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
dispatchDelay
),
queue) {
let now = dispatch_time(DISPATCH_TIME_NOW,0)
let when = dispatch_time(lastFireTime, dispatchDelay)
if now >= when {
action()
}
}
}
}

Now, in your actual class, your code will look like this:

let searchDebounceInterval: NSTimeInterval = NSTimeInterval(0.25)
let q = dispatch_get_main_queue()
func findPlaces() {
// ...
}
let debouncedFindPlaces = debounce(
searchDebounceInterval,
q,
findPlaces
)

Now debouncedFindPlaces is a function which you can call, and your findPlaces won't be executed unless delay has passed since the last time you called it.

How do you debounce a function after the first call?

Pure JavaScript processing:

Requiring a repeated call within the "debounce" period to be called in addition to the first call adds a complication that can be addressed using a timer in addition to timestamps to make immediate calls if possible.

However, because calls to a function may be delayed, it is not always possible to return a value from the function to the caller in real time.

The following concept code

  • calls the process "lock" in the sense of locking out calls in a predefined way.
  • returns undefined to all calls without implementing call backs to allow a caller to tell if its call was actioned or not, or to retrieve a return value;
  • When a call is made after a lockout period within which addition call attempts were made, the actual arguments used are to place a delayed call are those supplied by the most recent call attempt.





function CallLock( toCall, lockout) {

let argv;

let lastCall = 0;

let timer = 0;

function recall() {

timer = 0;

lastCall = Date.now();

toCall(...argv);

}

return function( ...args) {

let now = Date.now();

if(timer == 0) {

if( now >= lastCall+lockout) {

lastCall = now;

toCall( ...args);

}

else {

argv = args;

timer = setTimeout(recall, lastCall+lockout - now);

}

}

else {

argv = args; // use most recent arguments

}

}

}


// test CallLock

let start;

function demo( msg) {

console.log( "demo('%s') called. Time is %sms after start", msg, Date.now() - start);

}


let lockDemo = CallLock( demo, 1000); // 1 second lockout


start = Date.now();

lockDemo("call 1");

setTimeout( lockDemo, 200, "call 2");

setTimeout( lockDemo, 400, "call 3");

setTimeout( lockDemo, 1800, "call 4");

How to debounce a method in Angular

Okay, somehow I manage to solve the issue through setTimeout and it's working perfect for me as a debouncer,

onSliderEventChanges(event:ChangeContext){ 

if(this.timerid !== null){
clearTimeout(this.timerid);
}
this.timerid = setTimeout(() =>
{
this.foo(false);
this.timerid = null;
}, 400);

}

The first if will always clear the last running timeOut, so end of the sliding I will have only one call to the foo() as only the last timeOut is alive.

setTimeout always return atimerId.

How to implement a different debounce method that the function only called in the nth time

This implementation of debounce should help your use case. No global variable, and is implemented in pure javascript.

function _debounce(func, n){
let count = 0;
return (...args) => {
count++;
if (count % n === 0) {
count = 0;
func.apply(this, args);
}
};
}

const originFun = (sort) => {
console.log('hit,', sort)
}

const _call = _debounce((sort) => originFun(sort), 2);

_call(1) //not execute
_call(2) //hit,2
_call(3) //not execute
_call(4) //hit,4 */
_call(1) //not execute
_call(2) //hit,2
_call(3) //not execute
_call(4) //hit,4 */

Angular: How to debounce a function call with Observable.timer() and switchMap?

Use the debounceTime before subscribing to an observable.

In your filter function emit an event with the value and react in the subscription with added debounceTime.

filter(value: ValueType) {
this.filterSubject.next(value);
}

Outdated:

ngOnInit() {
this.filterSubject = new Subject<ValueType>();
this.filterSubject.debounceTime(500).subscribe((value: ValueType) => {
this.backendCall(value);
});
}

Newer Angular versions:

In newer Angular (or RxJS to be precise) versions, you need to pipe operators the following way:

ngOnInit() {
this.filterSubject = new Subject<ValueType>();
this.filterSubject.pipe(debounceTime(500)).subscribe((value: ValueType) => {
this.backendCall(value);
});
}

How to call debounce method within one function?

Not sure but maybe this is what you want

 const FirstAddTodo = type => {
setEditor({ ...editor, todoTitle: '' });

_.debounce(type => {
dispatch({ type, value: editor.todoTitle });
}, 1000)(type);
};

If you are confused, I can explain.

_.debounce will return a function and when you do SecondAddTodo(type) you are calling the retuned function, so if you add another () in the end of _.debounce, you are calling the returned function.

Here is an example on how to understand it better





let a = function (){ console.log('nested function'); }

let b = function (){ return a }

let c = function (){ return b }

let d = function (){ return c }


console.log(d)

console.log(d())

console.log(d()())

console.log(d()()())

console.log(d()()()())

Can someone explain the debounce function in Javascript

The code in the question was altered slightly from the code in the link. In the link, there is a check for (immediate && !timeout) BEFORE creating a new timout. Having it after causes immediate mode to never fire. I have updated my answer to annotate the working version from the link.





function debounce(func, wait, immediate) {

// 'private' variable for instance

// The returned function will be able to reference this due to closure.

// Each call to the returned function will share this common timer.

var timeout;


// Calling debounce returns a new anonymous function

return function() {

// reference the context and args for the setTimeout function

var context = this,

args = arguments;


// Should the function be called now? If immediate is true

// and not already in a timeout then the answer is: Yes

var callNow = immediate && !timeout;


// This is the basic debounce behaviour where you can call this

// function several times, but it will only execute once

// [before or after imposing a delay].

// Each time the returned function is called, the timer starts over.

clearTimeout(timeout);


// Set the new timeout

timeout = setTimeout(function() {


// Inside the timeout function, clear the timeout variable

// which will let the next execution run when in 'immediate' mode

timeout = null;


// Check if the function already ran with the immediate flag

if (!immediate) {

// Call the original function with apply

// apply lets you define the 'this' object as well as the arguments

// (both captured before setTimeout)

func.apply(context, args);

}

}, wait);


// Immediate mode and no wait timer? Execute the function..

if (callNow) func.apply(context, args);

}

}


/////////////////////////////////

// DEMO:


function onMouseMove(e){

console.clear();

console.log(e.x, e.y);

}


// Define the debounced function

var debouncedMouseMove = debounce(onMouseMove, 50);


// Call the debounced function on every mouse move

window.addEventListener('mousemove', debouncedMouseMove);


Related Topics



Leave a reply



Submit