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
Change iPhone Uislider Bar Image
Adding Navigation Bar Programmatically iOS
Autolayout - Make Height of View Relative to Half Superview Height
How to Disable Caching in Alamofire
iOS Simulator Games Run Very Slow (Low Fps)
How to Determine If an Nsdate Is Today
Rotation Methods Deprecated, Equivalent of 'Didrotatefrominterfaceorientation'
Nsmutableurlrequest Timeout Interval Not Taken into Consideration for Post Requests
Add Child View Controller to Current View Controller
Uicollectionview Adding Image to a Cell
What Is the Life Cycle of an iPhone Application
Uicollectionview Set Number of Columns
Metal - Resize Video Buffer Before Passing to Custom Kernel Filter