How are callbacks fired here? - javascript

Simple question,
How can I call this as a simple and basic function instead of a window.resize event?
$( window ).resize( debouncer( function ( e ) {
// do stuff
$('body').append('<p>done</p>');
} ) );
On window resizing I append a <p> element - However the debouncer function below, seems to be called first which debounces the window-resizing.
The question is much simpler than that, how do I call the debouncer as a function instead of calling it on window.resize? Does this has something to do with callbacks?
E.g I want to call a function in my code instead of on window-resize.
I figured I could remove , $( window ).resize and replace it with a function, e.g var greet = function and then call greet() to no avail.
This seems really basic but I don't get how functions are called between the debouncer, how it is called and how the debounced-code gets called.
The debouncer function that gets called on window.resize
(should be irrelevant, but I include it anyway):
function debouncer( func , timeout ) {
var timeoutID , slice = Array.prototype.slice , timeout = timeout || 200;
return function () {
var scope = this , args = arguments;
clearTimeout( timeoutID );
timeoutID = setTimeout( function () {
func.apply( scope , slice.call( args ) );
} , timeout );
}
}

Your debouncer function returns function. I think what you are trying to achieve, is call that function from code. If that is the case you can do as following:
var timeout = 100;
function debouncer_func( e ) {
// do stuff
$('body').append('<p>done</p>');
}
debouncer(debouncer_func, timeout)();
You can also do this as below:
debouncer(function(e){
// do stuff
$('body').append('<p>done</p>');
}, 100)();
Basically here your debouncer function is returning a function. So debouncer(args)() will call your returned function from debouncer.

Related

Run a function inside an anonymous function inside event listener

Just working on debounce feature and found this piece of code that seems to be doing the trick:
$(document).ready(function() {
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function searchUsers () {
// some code irrelevant to this question (...)
};
var myEfficientFn = debounce(searchUsers, 450);
document.getElementById("search").addEventListener('input', myEfficientFn);
});
Above seem to work well.
But I was curious if I can pass debounce function straight to addEventListener instead of saving it first in a variable myEfficentFn.
So I removed line var myEfficientFn = debounce(searchUsers, 450); from code and changed the last line to:
getElementById("search").addEventListener('input', function() {
debounce(searchUsers, 450);
});
but it stopped working. Why?
debounce is a function that, when called, returns another function, one which in your original code, is called when the event triggers:
var myEfficientFn = debounce(searchUsers, 450);
document.getElementById("search").addEventListener('input', myEfficientFn);
In contrast, in your second code, you're calling debounce inside the event listener. debounce returns a function, but you're never calling it: with
debounce(searchUsers, 450);
you have an unused function expression, kind of like having
const someVar = () => console.log('hi');
without ever using someVar later.
Pass the debounce call (which returns the function you want as the event listener) directly into addEventListener instead:
document.getElementById("search").addEventListener('input', debounce(searchUsers, 450));
The other answers left out a little bit of info that would help you understand what's happening:
getElementById("search").addEventListener('input', function() { // <--- this function gets called on click
debounce(searchUsers, 450); // this is a function, not a function call
});
getElementById("search").addEventListener('input', function(ev) { // <--- this function gets called on click
debounce(searchUsers, 450)(ev); // this is how you call the function returned by debounce
});
A short explanation;
The debounce function returns a function which is run by the event listener.
return function()
...
Your first approach saves the returned function to a variable and the even listener runs it.
addEventListener('input', myEfficientFn);
...
Your second approach gets the returned function within another function and no one really runs it.
debounce(searchUsers, 450); //WHo runs the returned function?
...
Solution in your own context - run the returned function!
getElementById("search").addEventListener('input', function(e) {
debounce(searchUsers, 450)(e);
});
you don't have to wrap it inside an anonymous function, you can simply use:
.addEventListener('input', debounce(searchUsers, 450))

Javascript force async callback of third party function that can execute sync or async

I have troubles to unterstand how the following function from this online javascript book (You-Dont-Know-JS) works? How does this function enable async behaviour when passed to a third party function (described in the next snippet) that may or may not execute async?
function asyncify(fn) {
var orig_fn = fn,
intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 )
;
fn = null;
return function() {
// firing too quickly, before `intv` timer has fired to
// indicate async turn has passed?
if (intv) {
fn = orig_fn.bind.apply(
orig_fn,
// add the wrapper's `this` to the `bind(..)`
// call parameters, as well as currying any
// passed in parameters
[this].concat( [].slice.call( arguments ) )
);
}
// already async
else {
// invoke original function
orig_fn.apply( this, arguments );
}
};
}
The link I provided also lists the following code example on how to execute asyncify(..):
function result(data) {
console.log( a );
}
var a = 0;
ajax( "..pre-cached-url..", asyncify( result ) );
a++;
Here ajax(..) is a third party function that may execute async or sync. To enforce an async callback of result(..) the author introduces asyncify(..) as an example. This will result in the console output always being 1 (async).
As far as I understand, the function fist defines two variables orig_fn to store the original function handle, result() in this case. And intv is the timer id returned from setTimeout.
var orig_fn = fn,
intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 )
;
setTimeout(..,0) means what exactly? To execute immediately in the next run of the event loop?
Why do we execute fn() in the callback function of setTimeout and the else statement in the return function? Isn't the function called twice this way when ajax operates async? First when the timer fires, which calls fn() and again when invoking orig_fn.apply(this, arguments)?
Why is asyncify returning a function but also calling the function fn passed to it?
What does the following in the if statement mean and does fn even get called if ajax is synchronous?
fn = orig_fn.bind.apply(
orig_fn,
// add the wrapper's `this` to the `bind(..)`
// call parameters, as well as currying any
// passed in parameters
[this].concat( [].slice.call( arguments ) )
);
Why is the parameter fn set to the original function? For me the variable fn is not even used after returning? Or is it a reference to result() which is now changed by adding this of the wrapper and the arguments? If so, why is this of the wrapper needed?
I guess my main problem to understand this function is how the flow of this code works depending on how ajax(..) works (async or sync). Could someone please explain both cases with the steps that happen in between?

jQuery - delaying all functions calls declared with .on

I am using the .on() function in jQuery to assign functions to events.
var someEvent = getEventName(someParams); // gets the event, like 'click'
var someFunctionReference = getFunctionNameBasedOnParams(someParams); // gets the function reference
$('.myElement').on(someEvent, someFunctionReference);
What I would like to do is wrap 'someFunctionReference' inside a timeout or delay its firing (by some time; lets say 250ms) without having to go and modify every single function that is returned by the method.
Is there a way to do this?
I'll assume you can't modify the code in getFunctionNameBasedOnParams, so all you need to do is create another function that returns a function wrapped in a timer.
function delayFunc(fn, ms) {
return function() {
var args = arguments;
setTimeout(function() {
fn.apply(this, args);
}, isNaN(ms) ? 100 : ms);
}
}
Then pass your function to it.
var someFunctionReference = delayFunc(getFunctionNameBasedOnParams(someParams), 250);
Be aware that your handler's return value is now meaningless, so if you return false, it'll have no effect.

setTimeout() problems on IE 9

I have a simple js structure like this :
var Waiting = (function () {
function Waiting() {
this.timer;
}
Waiting.prototype.show = function () {
var self = this;
clearTimeout( self.timer );
self.timer = setTimeout( function(){ self.hideLogo(); },3000);
}
Waiting.prototype.hideLogo = function () {
console.log("ok i passed timeout");
};
return Waiting;
})();
As expected, I get the "ok i passed timeout" log on every browser the first time I execute the show function (which called the hideLogo one). The problem appears in IE9 when I called for the second time the show function. This time, the hideLogo function is never called (log never appears in IE console). I tried a lot of things without any success.
If anyone as an idea...
When you're using setTimeout, the function that is being called looses the context: in other words this doesn't post to the instance on which the method is called anymore. You're using self to cancel this issue out, but self is, itself, an iffy word (as in reserved keyword). Perhaps use that, and use an IIFE in the setTimeout call:
this.timer = setTimeout((function (that)
{
return function()
{
clearTimeout(that.timer);//perhaps clear timeout here?
that.hideLogo.apply(that,[]);//double dutch, the apply _shouldn't_ be required
};
}(this)), 3000);
At first glance, that's the only thing I can see that might be the issue with your code: the clearTimeout call shouldn't be an issue, but I like to call it at the end of the timeout itself, and the self ambiguity thing. Let me know if this changes anything for you!
I am not really sure how you'd call show the second time with the code provided, maybe you create a new Waiting()?
Here is what worked for IE8
var Waiting=(function () {
function Waiting() {
this.timer;
}
Waiting.prototype.show = function () {
var self = this;
console.log("will clear pref timeout");
clearTimeout( self.timer );
self.timer = setTimeout(
function(){
self.hideLogo();
},30);
}
Waiting.prototype.hideLogo = function () {
console.log("ok i passed timeout");
};
return new Waiting();
})();
// shows only one time
Waiting.show();
Waiting.show();
// next one will show because it lets the prefious one
// finish without clearing the pref timeout.
setTimeout(function(){
Waiting.show();
},1000);
Try:
setTimeout( function(){
clearTimeout( that.timer );
that.hideLogo();
},3000);
Worked for me on IE and Chrome. IE is very behind on everything.

Get "this" element ID in jQuery live/delegate with timeout

I am trying to get the ID of an element bound with a jQuery delegate() function. I want to pass the element's ID to another function. The ID returned is always "undefined" and I'm not sure why. Here is my code:
$(document).ready(function() {
var timeout = undefined;
$('body').delegate(
'#tab-form input[type="text"]',
'keypress',
function(){
if(timeout != undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
timeout = undefined;
alert($(this).attr('id'));
}, 500);
}
);
});
And my markup:
<form id="tab-form">
<input type="text" value="" id="Tab_name" name="Tab[name]">
<input type="text" value="" id="Tab_text" name="Tab[text]">
</form>
Making a keypress in the text input pops up a JS alert that says "undefined", instead of "Tab_name" or "Tab_text" like I imagined it would.
My initial Googling around leads me to believe that the reason for the attr('id') being undefined is that "this" is not actually a single DOM element, but is an array of the elements that delegate() is attached to. I have not been able to figure out how to access the current bound element's DOM object in the jQuery object array.
Any help is much appreciated!
It's because this isn't what you want it to be in that anonymous function, it's window. There are a few ways to solve this, for example using $.proxy(), like this:
timeout = setTimeout($.proxy(function() {
timeout = undefined;
alert(this.id);
}, this), 500);
The context is window because window owns setTimeout. Just cache it:
$(document).ready(function() {
var timeout = undefined;
$('body').delegate(
'#tab-form input[type="text"]',
'keypress',
function(){
var el = this;
if(timeout != undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
timeout = undefined;
alert($(el).attr('id'));
}, 500);
}
);
});
meder already pointed out the reason for the behavior. You might also pass in the event object and use target:
$(document).ready(function() {
var timeout = undefined;
$('body').delegate(
'#tab-form input[type="text"]',
'keypress',
function(event){
if(timeout != undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
timeout = undefined;
alert($(event.target).attr('id'));
}, 500);
}
);
});
Sidenote: using .delegate() on the document.body does not make sense at all. You could just bind those events with .live() to your elements.
Since the other options are spoken for, I'll give the closure option. :o)
(function( th ) {
timeout = setTimeout(function() {
timeout = undefined;
alert(th.id);
}, 500);
})( this );
EDIT: To explain what is happening, basically you're creating a function, calling the function and passing in this as the argument to the function all at the same time.
Think of it this way:
// Create a new function that accepts one argument
function myFunc( th ) {
timeout = setTimeout(function() {
timeout = undefined;
alert(th.id);
}, 500);
}
// Immediately call the function, and pass "this" in to it
myFunc( this );
This is the exact same thing. Take this, wrap the entire function in (), make it anonymous by removing the name of the function myFunc, and then take the execution operator ( this ) from the function call, and place it directly after the function.
When you do that, you're essentially calling the function just after you've created it. It is just an easy way of immediately executing an unnamed (anonymous) function.

Categories