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.
Related
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.
I have three functions that all work with data from a global object. This global object gets filled with data from a local array in one function and with data from an ajax request with the second function. The third function relies on the data in the object, so the ajax request must have been completed.
I believe I am misunderstanding callbacks. Here's what I do:
var currentCharacter = {}
// this function gets the local data and then calls the second function
function loadData(getMarvelData) {
// do things to fill currentCharacter
getMarvelData(); // this is the callback to the next function (no ?)
}
// this function performs the ajax request, then calls the third function
function getMarvelData(getGoogleMap) {
// do ajax request and add stuff to currentCharacter
getGoogleMap(); // this is the callback to the final function (no ?)
}
function getGoogleMap() {
// do Google Map related stuff with data from currentCharacter
}
I thought setting a function as an argument of another function and then executing it would make the function dependent on the other before it continues. Clearly I still misunderstand callbacks after trying to make it work for a week now. As it is, the getMarvelData function doesn't even get called because I never see the alert popup and the currentCharacter object only has data from the loadData function.
Could somebody show the correct approach for my code, or if my approach of making these three functions is even the right one for this scenario.
The full repository is available at: https://github.com/ChaMbuna/Marvel-Map
V0.9 was actually working but the ajax call was set to run synchronous (it still is btw) Since then I've been overhauling my code to make it work asynchronously and to remove all jQuery (this is a Udacity project and removing jQuery was suggested by an instructor).
Appreciate the help
I have not enough reputation to put a comment, but a wild guess, you should remove the argument in loadData&getMarvelData or actually pass a function in calls to those function.
You have to pass the parameters correctly.
Try this:
var currentCharacter = {}
loadData(getMarvelData, getGoogleMap);
function loadData(f1, f2) {
// do sth.
f1(f2);
}
function getMarvelData(f2) {
// do sth.
f2();
}
function getGoogleMap() {
// do sth.
}
I havn't tested it, but it should work.
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);
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.