I am stuck on jQuery 1.4.3 on a current project and need some advice on how best to orchestrate the following..
Let's say I have two functions whom both perform ajax calls, and I only want to call the second one if the first one succeeds. With that said, there are also times in my application where I will call function a without needing to call function b. Therefore it wouldn't make sense to put the call to the second function within the first functions success method.
I'd like to do something like,
function doStuff(){
functionA().success( functionb() ).failure();
}
I typically orchestrate by using .done(); but that was introduced in jQuery 1.5, and again I am stuck on 1.4.3 for now.
Sure it makes sense to call it in the functionA() success handler. Just call it conditionally.
// Set a variable to determine if you will need to call functionB()
var youNeedToCallFunctionB = true;
// And call functionA()
functionA();
// Function definition:
function functionA() {
$.ajax({
url: ...,
success: function() {
if (youNeedToCallFunctionB) {
// Call functionB() in the success handler when needed...
functionB();
}
}
});
}
functionB() {
// Some other AJAX call...
}
Even better, pass a parameter to functionA() which determines whether or not to call functionB()
functionA(youNeedToCallFunctionB) {
// same thing as above, but pass the parameter
}
// Called as
functionA(true);
Related
I have the following jQuery code:
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(function(){
next();
});
$("#previous").click(function(){
previous();
});
This works, but this doesn't:
$("#next").click(next());
$("#previous").click(previous());
Why is this happening? Is there a problem in my code, or is this just a thing with jQuery? Note: #next and #previous refer to two buttons in my html file.
The callback should be a reference to the function.
Why $("#next").click(next()); doesn't work?
func() is a function call and not a reference, which is why it is called immediately.
This,
$("#next").click(function(){
next();
});
is a preferable way in case you need to pass arguments.
Else,
$("#next").click(next) //notice just the signature without ()
This works (if the functions next and previous are defined):
$("#next").click(next);
$("#previous").click(previous);
In this case the next and previous are also callback functions, the difference between the two is,
when you call this line
$("#next").click(next()); the function is executed immediately, and you are passing the result of the next function to the eventHandler of jQuery.
and in this case
$("#next").click(next); you are passing the function next to the EventHandler of jQuery.
Btw.: in the jQuery API Documentation (https://api.jquery.com/click/) it shows all parameters for the click function and the required types it states: "...handler Type: Function( Event eventObject ) A function to execute each time the event is triggered. ..."
try like this you will get your answer,
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(next);
$("#previous").click(previous);
working demo jsfiddle Example
What is going on there is a little bit obscured by the syntax of anonymous functions function() { ... }. What you are doing by that is passing a function, without calling it. And I want to explain how this works:
If you have a simple function
function next() { return 5 };
It will simply return the value 5, if you call it from somewhere:
a = next(); // value of a will be 5
But what you can do too, is to pass the whole function to a. This is possible, because functions in JavaScript are actually objects:
a = next;
b = a(); // value of b will be 5
If you look at the syntax, it shows you, that putting parentheses () at the end of a function invokes it, and returns the return value. While the naked string, without parentheses hands you the function itself.
So what is a callback now, and what does click() like to get as a parameter? A callback function is a function, that gets called later; we actually hand it over, to get called later. click() would like to get such a function as parameter, and it should be clear now, that we have to pass the function without parentheses, to enable click() to call it later, instead of just passing a 5 to it.
$("#next").click(next);
So how does then the initial syntax with the anonymous function work?
function() { next(); }
actually wraps your next() into another function, which is anonymous – because it does not have a name – but is working in the same way as a named function. You can even set a variable by it:
a = function() { next(); } // a will be the anonymous function that calls next()
But calling that function a() will return nothing, because the anonymous function does not return a value (To be exactly: every function call in JavaScript is returning at least undefined, but that's a technical detail).
It can even be called immediately by putting parenthesis at the end of it:
a = function() { return next(); }() // value of a will be 5
Adding the return there will make sure, the return value of next() will be passed through the anonymous function.
This should make clear why
$("#next").click(function(){ next(); });
is working, and why
$("#next").click(next());
is not, but
$("#next").click(next);
will be a good solution.
$("#next").click(next); would work. Notice parenthesis are not required as the function/callback handler should be passed as a parameter.
Wondering what the best solution to this problem is, also this is not my actual code structure or names but the simplest way to illustrate the problem.
I have a function which was purely used to perform an ajax call and load a template with jquery.
function load(template) {
$('#container').load(template, data, function() {
// complete code here
});
}
Focusing on the 3rd param in $.load(), namely a callback function that runs when the request is complete.
Now I have my load() function in another wrapper function:
function processTask(variable) {
load(variable);
}
The problem I have is I need some code to run after the ajax load is complete, however as my app has grown my wrapper function processTask may or may not invoke an ajax load so I can't perform my must needed code inside the complete callback.
Do I change my $.load() to perform synchronous or just manage my code better so that if I am calling a $.load() it puts my needed code in the callback and if not it places it where I need it to be?
I have read about javascript Promises and I'm unsure if they will help in this situation.
EDIT
So my processTask is an object method.
function classObj(name, fn) {
this.name = name;
this.processTask = fn;
this.load = function(template) {
$('#container').load(template, data, function() {
// complete code here
});
}
}
And in context I do this:
var task = new classObj('taskName', function() {
this.load('myFile.php');
// Or another function and not load() based on whats needed in the task.
});
Basically I have an object that I can add custom methods to at will and they can easily be called dynamically, until now they have always loaded a file.
First, change your load function to return the xhr from get (or ajax):
function load(template) {
return $.get('myFile.php', data, function(result) {
$('#container').html(result);
});
}
Then, within your code you can use when then to perform your code after the load completes if applicable:
var xhr;
/* ... */
if(something){
xhr = load(template);
}
/* ... */
if(xhr){
$.when(xhr).then(doSomething);
} else {
doSomething();
}
And in fact, this can be simplified using the fact that a non-deferred object passed to when (including undefined apparently) will execute the then immediately and get rid of the if:
$.when(xhr).then(doSomething);
If xhr is undefined then when will resolve immediately causing then to execute immediately.
In short, how do I let alert(1) run first:
$.post('example.php', function() {
alert(1);
})
alert(2);
alert(3);
alert(4);
But jquery ajax call seem like run in asynchronous method. So JavaScript will run everything below first, alert(2) to alert(4), then back to the post method, alert(1).
Certainly I can just put the code in the ajax function, but this make no sense when I have dozens of functions, then I would have to add the code to all functions.
$.post('example.php', function() {
alert(1);
example();
})
function example() {
alert(2);
alert(3);
alert(4);
}
I want to get some json data from an ajax call, and use it later. So is there any smart solution?
2021-08-25
after 8 years, introduction of async / await is awesome, i don't really use jquery anymore, so i didn't test the code
await Promise.resolve($.post('example.php', function() {
alert(1);
example();
}));
alert(2);
alert(3);
alert(4);
in jQuery I simply prefer to use $.when and $.then it's easy to do and code is more readable using this.
function CatchTheFish(){
console.log('we are catching the fish');
}
function EattheFish(){
console.log('now time to eat this fish');
}
$.when ( CatchTheFish() ).then( EattheFish() );
This code is work in latest version of jQuery 1.9.1
"Certainly I can just put the code in the ajax function, but this make no sense when I have dozens of functions, then I would have to add the code to all functions."
There are many patters that can make this easier, but if you're saying that dozens of functions may need to call this post, you could just put the post in a function, and have the function receive a callback.
function myPost(callback) {
$.post('example.php', function(data) {
alert(1);
callback(data);
})
}
// These are your "dozens of functions"
function a2() { alert(2); }
function a3() { alert(3); }
function a4() { alert(4); }
// These would be at various places in your application
myPost(a1);
myPost(a2);
myPost(a3);
Ultimately the best approach depends on what you mean by "dozens of functions", but certainly you won't need to do the hard coding that you seem to imply.
Passing functions as arguments is often the way to go, but there are other patterns as well that will set up a queue if that's what's needed.
The reason the alerts are firing in that order is because the "A" in AJAX stands for Asynchronous.
Here is how the code executes:
The post method sends a request to the server, the second parameter is a callback function which will be called later once the request is returned by the server.
It then proceeds to the next line of code after the post call, firing alert(2);
Then the next line firing alert(3);
Then the next line firing alert(4);
This block of code is done running so control returns to the event loop
Once the server returns the Ajax request, the callback function is called firing alert(1)
The best way to solve this would probably be to just move all of the code inside of the callback, that way it will only run once the request has been returned.
$.post('example.php', function() {
alert(1);
alert(2);
alert(3);
alert(4);
})
There probably isn't a need to put it in another function and call it as you suggested at the end of your question.
I would avoid "synchronous" Ajax requests, aside from being an oxymoron, they run counter to the whole purpose of using Ajax. Using Ajax should make your application more responsive, using synchronous requests does the opposite, it can cause the browser to lock up if a request timesout or takes a longtime to return from the server.
Here's an alternative that makes use of jQuery's custom events. It's basically like the other non-synchronous-suggesting answers, just looks slightly different and may help you keep our code nice and clean...
Use an object to bind a custom event to. Bind one or more handlers using the on method of jQuery on that object. Trigger the custom event at the end of your asynchronous function and jQuery will do the rest for you.
Example:
(function($){
var fakeAsync = {};
function fakeAsyncFunction( ) {
alert(1);
$(fakeAsync).trigger('customDone');
}
function a( ) {
alert(2);
}
function b( ) {
alert(3);
}
function c( ) {
alert(4);
}
window.setTimeout(fakeAsyncFunction, 1000);
$(fakeAsync).on('customDone', a)
.on('customDone', b)
.on('customDone', c);
})(jQuery);
Working fiddle.
I have an asynchronous Ajax function which runs a command string at the server side and returns the result to the client. It calls a callback to process the result.
function ajaxCall(commandStr,callback){
var url=......//make a url with the command string
jquery.get(url,function(result){
//process the result using callback
callback(result);
});
}
The asynchronous call (ajaxCall) may take a while to be finished but I want it to do the same command after an interval (1000ms).
I want to write a function that is like this:
function ajaxCallRepeated(interval,commandStr,callback)
I tried closures like this:
function ajaxCallRepeated(interval,commandStr,callback){
//This feature uses closures in Javascript. Please read this to know why and how: http://jibbering.com/faq/notes/closures/#clSto
function callLater(param1,param2,param3){
return (function(){
ajaxCall(param2,function(out,err){
if(param3)param3(out,err);
var functRef = callLater(param1,param2,param3);
setTimeout(functRef, interval);
});
});
}
//the first call
var functRef = callLater(interval,commandStr,callback);
setTimeout(functRef, interval);
}
Then I call it like this:
ajaxCallRepeated(2000,"ls",function(result){
alert(result);
});
But it only runs the command 2 times.
How can I write a function that will reschedule itself after it is called as a callback of an asynchronous function?
PS. I want to fire another Ajax call after the previous one is finished. Also, it worth to mention that axashCallRepeated() will be called with various parameters, so several Ajax calls are running in parallel, but for each commandStr, there is only one Ajax call going on, and after the Ajax call returns, another one will be fired after X seconds.
I would not use setTimeout to trigger the second Ajax call ! Because you never know how long it will take and if it's finished !
As far as you tagged your question right and you ARE using jquery you should consider something like this:
$.ajax({
type: 'POST',
url: url,
data: data,
success: function(){
// The AJAX is successfully done, now you trigger your custom event:
$(document).trigger('myAjaxHasCompleted');
},
dataType: dataType
});
$(function(){
//somehwere in your document ready block
$(document).on("myAjaxHasCompleted",function(){
$.ajax({
//execute the second one
});
});
});
So this would ensure that the ajax post is DONE and was successful and now you could execute the second one. I know its not the exact answer to your question but you should consider on using something like this ! Would make it safer I guess :-)
The key to solve this problem is to save a reference to the closure itself and use it when scheduling the next call:
function ajaxCallRepeated(interval,commandStr,callback){
//This feature uses closures in Javascript. Please read this to know why and how: http://jibbering.com/faq/notes/closures/#clSto
function callLater(_interval,_commandString,_callback){
var closure=(function(){
ajaxCall(_commandString,function(out,err){
if(_callback)_callback(out,err);
setTimeout(closure,_interval);
});
});
return closure;
}
//now make a closure for every call to this function
var functRef = callLater(interval,commandString,callback);
//the first call
functRef();
}
It becomes easier to reason about if you separate things up a bit.
For example, the repetition logic doesn't have to know about AJAX or callbacks at all:
function mkRepeater(interval, fn, fnScope, fnArgs) {
var running;
function repeat() {
if (!running) return;
fn.apply(fnScope, fnArgs);
setTimeout(repeat, interval);
}
return {
start: function() { running = true; repeat(); },
stop: function() { running = false; }
};
}
You can use it like this:
var r = mkRepeater(2000, ajaxFunction, this, ["getStuff", callbackFn]);
r.start();
...
r.stop();
If I use a closure to define something is there a means of waiting so to speak until the variable is populated before moving on to the next bit.
Example:
var myVari = someFunction();
$.each(myVari, function(){/*code for each*/});
the function that defines myVari is an AJAX call, which can take a second or 4 (yea its not to fast) to define the variable. Problem is, before the AJAX call yields its results the $.each has already fired off and errored due to myVari being empty. Is there a better way to approach this scenario?
You should adapt your code so that you can pass a callback to someFunction, which you execute when the AJAX call is completed.
The only way you can wait for the AJAX call to complete is to change the call to synchronous, but this is heavily discouraged as it locks up the browser completely for the duration of the AJAX call.
Because you are already using the jQuery libary, this process of callbacks becomes a whole lot easier. Instead of returning the variable like you are at the moment, I'd return the jQuery AJAX object (which has a promise interface as of 1.6), so you can easily add callbacks to it:
function someFunction () {
return jQuery.ajax('some/url.php', {
// whatever
});
}
var myVari = someFunction();
myVari.done(function (data) {
$.each(data, function(){/*code for each*/});
});
If I understand what you are trying to do, then you could try your $.each inside the 'success' handler of your ajax call.
Rewrite someFunction to something like -
var myVari; //define this here or in whichever calling scope where it needs to be available.
$.ajax({
'url': 'http://..',
'type': 'GET', // or POST
'data': { } // whatever data you need to send
'success': function(data) {
myVari = process_the_server(data);
$.each(myVari, function() {...});
}
});
Use a callback, like this:
someFunction(function(myVari) {
$.each(myVari, function(){ /*code for each*/ });
});
Then redefine someFunction like this:
function someFunction(callback) {
var myVari;
/* ... */
/* calcuate myVari */
/* ... */
/* instead of returning it, pass it to the callback: */
callback(myVari);
}
The correct way is: Instead of running the each on its own, run it inside the ajax call.
You could, I suppose do:
function checkFunc() {
setTimeout(function() {
if(myVari) {
$.each(........);
} else {
checkFunc();
}
}, 1000);
}
That not really good coding practice, but it will work.