So all the examples I've seen with promises or callbacks usually involve injecting the callback into the asynchronous function inside of the setTimeout or something like that. But what if you have a function that you can't modify for whatever reason. Maybe it's imported from a library, idk. Imagine this code.
const funcA = () => {
setTimeout(() =>console.log("first"), 500)
}
const funcB = () => {
console.log("second");
}
funcA();
funcB();
How do you get second to print after first, without modifying funcA?
TLDR: Abandon the code.
All async functions in javascript either return a promise or accept a callback. This has been the culture in javascript since the mid 2000s. If you ever encounter the situation in your question the best solution is to not use that library and find something else.
Workaround..
However, there are times when you need to do something like this. For example if you develop a mashup script that can be inserted by the user into his HTML and you have no control how the user copy/paste your code.
One workaround is to use setTimeout or setInterval to monitor something for change. This can be a variable, a <div>, an <input> etc. Here's a silly example that waits for jQuery to load:
const funcB = () => {
console.log("second");
}
function waitForJQuery () {
if (window.jQuery || window.$) { // check if jQuery variable exist
console.log('jQuery loaded');
funcB();
}
else {
setTimeout(waitForJQuery, 200); // check 5 times per second
}
}
waitForJQuery();
Normally you would not write code like this. But IF and only if you have no other choice you can do something like this.
Note though that this requires whatever you are waiting for to generate a side effect: either creating a global variable or modifying a global variable or updating the DOM etc.
Related
I've been trying to read as much as I can about javascript callbacks and jquery deferred objects but apparently things just aren't clicking for me. It seems to make a vague amount of sense when I read through it and practice examples, but when I try to apply it to my specific problem, I'm just hitting a wall. If anyone can understand what I'm trying to do and offer ideas, it would be much appreciated!
Here's some existing code:
$(document).ready(function() {
firstFunction();
secondFunction();
});
For the sake of keeping things simple here, I won't get into what firstFunction() and secondFunction() do, but suffice it to say that they both perform asynchronous work.
Here's my problem:
firstFunction() is dependent on the document being ready so needs to be inside $(document).ready(function() { }. secondFunction() isn't dependent on $(document).ready(function(), but should only execute after firstFunction has completed. I'm hoping to do all the computation for secondFunction() before the $(document).ready(function() { } block, but only execute it after firstFunction() has completed. This way firstFunction and secondFunction will execute in a more visually seamless manner. So basically, I'd like to do something like the following pseudo code:
var deferredSecondFunction = secondFunction().compute().defer(); //perform computation for secondFunction but defer execution
$(document).ready(function() {
firstFunction().done.execute(deferredSecondFunction().execute()); //finally execute secondFunction once firstFunction has completed.
});
Does anyone know if this is even possible? An important caveat is that I need to do this without the Javascript Promise object, since, for reasons outside the scope of this question, the webkit I'm working with is an old version. If anyone could help me understand this it would be appreciated!
The code shown uses a callback function and a self-invoking anonymous JavaScript function such has:
var calculatedObject;
(function(){
// Will be executed as soon as browser interprets it.
// write code here & save your calculations/operations
calculatedObject = { ... };
})();
function firstFunction(callback){
// Do stuff
callback();
}
function secondFunction(){
// Do more stuff
// Use your calculations saved in the calculated object.
}
$(document).ready(function(){
firstFunction(secondFunction);
});
This way the second function will only be called at the end of the first one.
you can use a callback..
function f1(){
//do some stuff
}
function f2(callback){
// do some async stuff
callback();
}
f2(f1);
this example passes one function to another function. the second function then calls the first whenever it's ready.
I'm writing a basic wrapper for the Webkit Storage API (the new version of this API) for me to use. My current problem with it is the queryUsageAndQuota() function.
My wrapper around that particular function originally looked like this:
self.pers.getQuota = function() {
self.pers.queryUsageAndQuota(function(usage,quota) {
return quota;
});
}
// self is a reference to the top level of this 'wrapper'
Hence, I would have called var quota = self.pers.getQuota(); and had the quota returned.
After that failed, I had a look at this question and changed it so I used a user-defined callback instead. Now the function is this:
self.pers.getQuota = function(callback) {
self.pers.queryUsageAndQuota(function(usage,quota) {
callback.call(quota);
});
}
However, executing this line:
self.pers.getQuota(function(quota) {
console.log(quota);
});
shows undefined in the log. I can't figure out why, because when I execute the underlying function navigator.webkitPersistentStorage.queryUsageAndQuota(), I get the right number out of it.
.call doesn't work like you think it does. Instead do callback.call(null, quota).
The actual signature for both Function.prototype.call (and similarly for apply) is
Function.prototype.call(valueOfThis, valueOfParam1, valueOfParam2, ...);
This is also why I often say that the this keyword in javascript is stupid and you should avoid using it. It simply is another parameter like all the others, You just don't get to specify a name for it. It's a vestige of javascript's creation when Netscape mandated that this Scheme-based language look like Java.
Incidentally, you could use the third way of invoking methods here. Simply
callback(quota);
This however has the side effect of making javascript take a guess at what you want this to be (the global window object in this case). As long as you don't use this, the simple syntax works great.
If you actually really want to return a value rather than passing a callback look into javascript promises. I can't tell you which one to use without knowing what environment you in and what libraries you're using but jQuery has a good implementation in the Deferred object
Try
self.pers.getQuota = function(callback) {
self.pers.queryUsageAndQuota(function(usage,quota) {
callback(quota);
});
}
Or
self.pers.getQuota = function(callback) {
self.pers.queryUsageAndQuota(function(usage,quota) {
callback.call(/* an object as 'this'*/, quota);
});
}
Function.prototype.call()
Or
self.pers.getQuota = function(callback) {
self.pers.queryUsageAndQuota(function(usage,quota) {
callback.apply(/* an object as 'this'*/, [quota]);
});
}
Function.prototype.apply()
Since I'm using this type of call often I wish to make this reusable:
function getJSON(cmd){
$.getJSON(cmd, function(data) {
}).done(function(data) {
return data;
}).fail(function() { console.log('Server failed!') });
}
I hoped to use it like this:
function susbcribe(id){
var cmd = 'subscribe.php?='+id;
var obj = getJSON(cmd);
console.log(obj);
}
But javascript runs console.log before the async json can even return anything to obj.
Just to be clear - i know i can execute code inside of .done(), but because I use this often I wish to forgo rewriting the same function over and over.
So the question is: is there a way to make js stop and wait for getJSON to finish and return something to obj ?
As things currently stand, you will have to at least write the done function every time. You can't escape callback hell by pretending it doesn't exist.
There are ways to avoid some of it by using promises cleverly, but for simple things, this is pretty much as simple as it gets. Until we get support for generators/iterators some time in 2025.
You could set the fail function as a global "ajax event" handler to avoid having to type error handling every time.
I'm debugging an app that uses .NET's scriptmanager.
It may be a glitch in firebug, but when I read through the code there are a lot of lines like the following:
// anonymous functions not attached as handlers and not called immediately
function () {
//code
}
// named functions added as methods
myObj = {
myMethod: function myFunctionName() {
//code
}
}
Are these lines valid and, if so, what do they do and what possible reason would there be for coding like this (and I won't accept "It's microsoft - what d'you expect" as an answer)?
This might be worth a read: How does an anonymous function in JavaScript work?
They are there because some busy programmer was intending to do something and ran out of time, but left the stub as a reminder of work to be done. They do nothing as of yet.
or to watermark the code for checks that are done elsewhere in the logic
or simply put there to obfuscate...
I have multiple document.ready functions on a page and I want a function to be called when all my document.ready functions have been executed. I simply want the function to be called
at the very end, after all other document.ready functions have executed.
An example of this could be that each document.ready function increments a global variable when it has been executed, and the last function needs to check the value of that variable at the very end.
Any ideas ?
This will be enough:
$(function () {
window.setTimeout(function () {
// your stuff here
}, 0);
});
This postpones the execution of your function after all other in the document ready queue are executed.
First idea (for small apps): Tidy up
You can just put everything in one $().ready() call. It might nieed refactoring, but it's the right thing to do in most cases.
Second idea: A Mediator [pattern]
Create a mediator class that will register functions and call its register() instead of $().ready(). When all functions are registered You just loop over the collection and run them in the single and only $().ready() and You have a point in code that is just after all is executed.
I am currently developing a kind of a framework for jquery applications that has a mediator. I might stick together a small version including the mediator if You're interested.
Why not just calling it after all the others ?
$(function(){
func1();
...
funcN();
functionThatNeedsToBeCalledAfter();
});
Of course you will have to cleanup your code to have only 1 place where the document ready function is used... but then your code would be more readable so it's worth it.
little hacky but might work, create a variable inside jquery scope like that
$.imDone = false
then create a function with setTimeout called after short time to lookup for the variable ser to true
var theLastFunctionToCall = function(){
alert('I m the last being called!')
}
var trigger = function(){
$.imDone?theLastFunctionToCall():window.setTimeout(trigger,10);
}
trigger();
I only recommend this when u have different $(document).ready in different big js files, but if you can refactor i sincerelly recommend an optimal solution.