Using .promise() to have the Ajax request start first? - javascript

I was advised to use .promise() in this function because as it is now, the Ajax call won't start until the loading animation has finished. I read through the codex, but couldn't really understand how to implement it. Can someone show me how it's done?
function projectShow() {
$('#loading-animation').show(100, function() {
$.ajax({
type: 'POST',
cache: false,
url: ajaxURL,
data: {'action': 'load-content', post_id: post_id },
success: function(response) {
$('#project-container').slideDown('fast').html(response);
$('#loading-animation').hide();
return false;
}
});
});
}

The advice to use .promise() was probably given because your code forces a small 100ms delay before making the AJAX call (while the animation runs to completion). It may make more sense to make the AJAX call, then start the animation while waiting for the response.
I have modified your code to achieve this by simply making the AJAX call before starting the animation. (jQuery.ajax() uses .promise() internally by default. See the async option for more information.) Be aware that in cases where the AJAX call returns in less than 100ms, the execution order of your JavaScript may be altered. This may cause undesired side-effects, but I think it is OK in your case.
function projectShow() {
$.ajax({
type: 'POST',
cache: false,
url: ajaxURL,
data: {'action': 'load-content', post_id: post_id },
success: function(response) {
$('#project-container').slideDown('fast').html(response);
$('#loading-animation').hide();
return false;
}
});
$('#loading-animation').show(100);
}

Related

Keeping AJAX Requests Serial in jQuery

I have some code that I recently moved to FastCGI for a backend to fulfill AJAX requests from a jQuery based front end. The problem is that while FastCGI largely accelerates it, I actually get a negative performance issue from two jQuery AJAX requests hitting it in too quick of succession. What I'd like to do is "lock" AJAX so that the requests happen in serial rather than parallel -- each request only takes around 180ms to perform, but if the second request goes in before the first one has completed, the second request ends up taking about a second and a half instead.
I suppose the obvious way that I could make it serial is to put an $.ajax request inside the .done portion of the previous request, but the requests are in to different functions and need to stay that way since they don't always need to be fired together -- just frequently so. Imagine this:
function loadCategories () {
// Do some organizing stuff, set url, etc.
$.ajax({
url: url,
data: parameters,
type: "GET",
dataType : "json",
})
.done(function( json ) {
//process sidebar category data.
});
}
function loadArticles () {
// Do some organizing stuff, set url, etc.
$.ajax({
url: url,
data: parameters,
type: "GET",
dataType : "json",
})
.done(function( json ) {
//process article data.
});
}
Both of these functions are called in a third function:
function loadPage (parameters) {
loadCategories(parameters);
loadArticles(parameters);
}
What I'd like to do is keep the .done and .always logic within those two functions, but also return a promise from these functions so that I could then use $.then to keep loadArticles from firing until loadCategories has completed. I've tried to figure out the right way to do this, but haven't succeeded in the right way to do this yet.
Have the functions return the Deferred object that $.ajax() returns, and then you can wait for this in the calling function.
function loadCategories() {
// Do some organizing stuff, set url, etc.
return $.ajax({
url: url,
data: parameters,
type: "GET",
dataType: "json",
})
.done(function(json) {
//process sidebar category data.
});
}
function loadArticles() {
// Do some organizing stuff, set url, etc.
return $.ajax({
url: url,
data: parameters,
type: "GET",
dataType: "json",
})
.done(function(json) {
//process article data.
});
}
function loadPage(parameters) {
$.when(loadCategories(parameters)).then(
function() {
loadArticles(parameters)
};
});
}

Wait for Async ajax to complete before moving onto other code?

I know this has been asked, probably, a million times, but for the life of me I cannot get anything to work.
I have a UI wizard control that on the "changed" event validates the model. If the model is not valid, it doe not allow the user to move forward in the wizard. I have tired using the $.when().done() feature in jquery, but my code still passes through before making sure the model is valid. The reason for calling an async ajax request is I do not want the UI to lock up so I can show some sort of progress indicator. I had set the async property to false, but my UI indicator would never show up. Here is an example of what my code is doing:
//the change event that is called when the user clicks 'next' on the wizard:
wizard.on('change', function (e, data) {
var isValid = $.validate({
"Model": [The_UI_MODEL],
"Url": [URL_To_Server_Validation],
"Async": true, //tells ajax request to send as async
});
//Tells the wizard not to move 'next' if the request comes back as not valid
if (data.direction === 'next' && !isValid) {
e.preventDefault();
}
}
//I am using the $.extend method for JQuery to create a function that will validate any model in my system.
validate: function(options) {
//Clear any previous validation errors
$.clearValidations();
var data = $.postJson(options);
//the result is getting returned before the $.postJson(options) finishes
return data.Success;
}
//I created my own method that extends the $.ajax method so I could do other things before /after a request:
postJson: function(options){
...other code for my application
//This is where I want the ajax request to happen and once done return the data coming back
//This is what I have tried, but it is not doing what I thought.
$.when(function(){
return $.ajax({
url: options.Url,
type: 'POST',
cache: false,
async: options.Async,
timeout: options.Timeout,
contentType: 'application/json; charset=utf-8',
dataType: "json",
data: JSON.stringify(options.Model),
error: function(xhr, status, error) {
...do stuff if ajax errors out
},
success: function (data) {
},
});
}).done(function(response){
//looks like i get back the responseText of the request. which is fine, but other posts i have read stated i should be getting back the request itself
...other UI stuff
return response;
})
}
KarelG is absolutely right. You need to refactor your code and do your valdiation check within the success callback of the ajax request.
Something like this...
wizard.on('change', function (e, data) {
$.ajax({
url: [URL_To_Server_Validation],
type: 'POST',
cache: false,
async: true,
contentType: 'application/json; charset=utf-8',
dataType: "json",
data: {"Model": [The_UI_MODEL]},
success: function (response) {
//Tells the wizard not to move 'next' if the request comes back as not valid
if(!response & data.direction === 'next')
{
e.preventDefault();
}
}
});
});
It looks like you're trying to write asynchronous code as if it were synchronous. An asynchronous call such as your $.validate() will return immediately without a result and continue on to the rest of your code. Anything you want to happen when the validate call finishes must be done in a callback function passed to it.
You can use jQuery promises (when, then, done, etc.) or another library such as async.js to help manage the control flow.
Also, this isn't particularly useful now since there's little to no browser support for it yet, but the yield operator plus a library such as Task.js will eventually let us write asynchronous code as if it were synchronous.

Can't get JQuery $.ajax() to work entirely synchronously

UPDATE Following #Ryan Olds suggestion to include the setTimeout in the callback, I must clarify that in my production code I'm calling multiple urls to get json data from several sites. (Have updated JavaScript code below).
Is it only possible to have multiple timeouts scattered throughout this function?
I have a self-invoking updateFunction as follows:
(function update() {
$.ajax({
type: 'GET',
url: "http://myexample.com/jsondata",
dataType: 'json',
success: function (data) {
// do some callback stuff
},
async: false
});
$.ajax({
type: 'GET',
url: "http://myexample2.com/jsondata2",
dataType: 'json',
success: function (data) {
// do some further callback stuff
},
async: false
});
setTimeout(update, 2000);
})();
What I expected this code to do
I hoped that this function would go off to the target URL and wait for the result, then deal with the success callback. Then (and only then) would it fall through to set a 2 second timeout to call the function again.
What appears to be happening instead
Instead, the GET request codes out, and before the response has been dealt with, the timeout has already been set.
What am I missing? How can I make this entirely synchronous?
If I were you, I'd make use of jQuery's support for deferred action.
(function update() {
$.when($.ajax({
type: 'GET',
url: "http://myexample.com/jsondata",
dataType: 'json',
success: function (data) {
// do some callback stuff
}
}), $.ajax({
type: 'GET',
url: "http://myexample2.com/jsondata2",
dataType: 'json',
success: function (data) {
// do some further callback stuff
}
}), $.ajax({
// more requests as you like
})).then(function() {
// when all the requests are complete
setTimeout(update, 2000);
});
}());
Much nicer, IMHO, than mucking around with synchronous requests. Indeed, if the requests are cross-domain, this is pretty much your only option.
See
$.when
deferred.then
Move the timeout in to the success callback. The request is synchronous, it would appear the the callback is not.
I would modify the setup like so:
function update() {
$.ajax({
type: 'GET',
url: "http://myexample.com/jsondata",
dataType: 'json',
success: function (data) {
// do some callback stuff
},
async: false
});
$.ajax({
type: 'GET',
url: "http://myexample2.com/jsondata2",
dataType: 'json',
success: function (data) {
// do some further callback stuff
},
async: false
});
}
setInterval(update, 2000);
update(); // only necessary if you can't wait 2 seconds before 1st load.
You cannot make it entirely synchronous because you're setting up calls to alternate domains. That's done (internal to jQuery) by creating <script> tags and adding them to the document. Browsers perform those calls asynchronously, and that's that. You can't make ordinary xhr requests to domains different from your own.
I can't imagine why you'd want something like that to be synchronous, especially since you're doing many of these operations.
I don't think async: false works on cross domain requests.
From the docs:
async Boolean
Default: true
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active.
In any case, maybe you can set some conditionals to fire the requests in the order that you want.

Real-time load result (ajax)

I dont know how write this script. I need load results with some URL (eg: localhost/index.php?action=get&type=29) and this result to give a variable for further processing. I need create this on Jquery. Thanks.
There are features in jQuery that can be used, you have either a quick load using the simple .load() function that will parse the HTML into an element. Usage:
$('#element').load('http://www.urlgoeshere.com/');
With processing events with AJAX with further writing options, you have many options to choose from:
http://api.jquery.com/jQuery.ajax/
These options below are using the .ajax() function but makes the writing easier:
http://api.jquery.com/jQuery.get/
http://api.jquery.com/jQuery.post/
EDIT: With your "refresh", you can use the setTimeout function to repeat the ajax call:
setTimeout(function()
{
$.ajax({
type: "POST",
url: "some.php",
data: "action=get&type=29",
success: function(arg){
// do something
}
});
}, 1000); // This will "refresh" every 1 second
$.ajax({
type: "POST",
url: "some.php",
data: "action=get&type=29",
success: function(arg){
// do something
}
});
you can use
$.ajax({
url: "localhost/index.php",
data: "action=get&type=29",
success: function(data, status, xhr){
// data is the response from the server, status is the http status code,
// xhr is the actual xhr
},
error: function(){
},
...
});
to get the results.
Be sure to define the success and error callbacks to process the data when it is returned.
Look here http://api.jquery.com/jQuery.ajax/ to get started.

Why am I unable to retrieve the calculated height of content inserted in response to a jQuery AJAX request?

I am sure this has been discussed repeatedly, but I am stumped. I am using jQuery to make an AJAX call to an ASP.NET Web service which returns some HTML. That part is working fine.
I want to do some calculations on the height of the HTML returned, but when the the call happens for the first time I am getting a height of 0. I know my calculation are just happening before the AJAX call is complete, because on the second attempt it works. If I clear cache then it returns 0 again.
I need to fire an event after the html is rendered. I have tried both global and local events like ajaxComplete.
$.ajax({
type: "POST",
url: "Webservices/Service.asmx/HelloWorld",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
$("#OverlayContent").html(msg.d);
}
complete: function(msg) {
alert($("#OverlayContent").height());
}
});
I appreciate any help.
Sounds like your height calculation is running before the html is inserted and rendered in the DOM. Make sure to stagger it with a setTimeout call or an interval. For example:
$.ajax({
type: "POST",
url: "Webservices/Service.asmx/HelloWorld",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
$("#OverlayContent").html(msg.d);
setTimeout(function(){ getHeight();},100);
}
});
function getHeight(){
// If our height is 0, set a new timeout and we'll check again
if($("#OverlayContent").height() === 0){
setTimeout(function(){ getHeight() }, 100);
}
else{
alert("The height is: " + $("#OverlayContent").height());
}
}
You need to poll on the html being inserted into the DOM and rendered.
In all likelihood the complete event is firing simultaneously if not before the success event, since complete fires as soon as the AJAX data is finished being received. The success event is fired once it receives return data with the 200 OK status code.
You could use a delay, but personally I think using jQuery's queue() method would be better:
success: function(msg) {
$("#OverlayContent").html(msg.d).queue(function(){
alert($("#OverlayContent").height());
$(this).dequeue();
})
}
The dequeue() at the end there is important to restore the normal flow of things.
At that point you just get rid of the complete callback entirely.
I may not be understanding your question entirely, but you could try setting the update code in an timeout that runs immediately after the completed event...
//..your other code here
complete:function(m) {
setTimeout(function() {
alert($("#OverlayContent").height());
},1);
}
//...the rest of your code

Categories