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

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.

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)
};
});
}

How to access ajax jsonp results data in order to return true or false?

I have a function that needs to either return true; or return false; which contains an ajax call that is the method for determining the conditional result based on the response.
My problem is scoping and I'm not sure how to get out of this one. If I setup as a callback, then the return statement lives within the callback function itself and doesn't execute within the main wrapper function.
How should this be setup to execute correctly? Do I need to completely restructure?
function() {
var response;
$.ajax({
dataType: 'jsonp',
url: 'https://apilayer.net/api/check?access_key=',
async: false,
success: function(json) {
response = json.score;
}
});
if (response == 1) {
return false;
}
};
dataType: 'jsonp',
async: false,
JSONP requests cannot be made syncronously, so async: false is ignored.
If you weren't making a JSONP request, then using async: false would still be a bad idea (the underlying feature it depends on is deprecated for good reason).
This means that you can't do what you want.
The answers to How do I return the response from an asynchronous call? describe strategies for dealing with this.
First of all, 'async = false' is not supported anymore so call will be async in nature.
Now, you have two options:
initialize conditional var i.e. response with some value. So even if
ajax response is not received, you will not face any error on if
condition.
put conditional statement inside callback.
If your condition is based on ajax response, then ideal way would be to put it inside callback function.
Hope it helps!
if you use async false the request will become synchronous and the code will not be executed until the request is completed. this will slow down the browser.
var response = $.ajax({
dataType: 'jsonp',
url: 'https://apilayer.net/api/check?access_key=',
async: false,
success: function(json) {
response = json.score;
}
});

How to run getJSON synchronously? [duplicate]

GOAL: What I'm after is to get data from database and refresh main.php (more evident through draw_polygon) every time something is added in database (after $.ajax to submit_to_db.php).
So basically I have a main.php that will ajax call another php to receive an array that will be saved to database, and a json call another php to return an array will be used by main.php.
$(document).ready(function() {
get_from_db();
$('#button_cancel').click(function(){
$.ajax({
url: 'submit_to_db.php',
type: 'POST',
data: {list_item: selected_from_list},
success: function(result){
...
get_from_db();
}
});
});
function get_from_db(){
$.getJSON('get_from_db.php', function(data) {
...
draw_polygon(data);
});
}
});
In my case, what I did was a get_from_db function call for getJSON to actually get data from database, with the data to be used to draw_polygon. But is that how it should be done? I'm a complete newbie and this is my first time to try getJSON and ajax too to be honest. So my question: How does asynchronous work actually? Is there another workaround for this instead of having to call function get_from_db with getJSON (it isn't synchronous, is it? is that why it doesn't update the page when it isn't within a function?) All the time - like $.ajax with async: false (I couldn't get it to work by the way). My approach is working, but I thought maybe there are other better ways to do it. I'd love to learn how.
To make it more clearer, here's what I want to achieve:
#start of page, get data from database (currently through getJSON)
Paint or draw in canvas using the data
When I click the done button it will update the database
I want to AUTOMATICALLY get the data again to repaint the changes in canvas.
Since $.getJSON() uses ajax configurations, just set the global ajax configs:
// Set the global configs to synchronous
$.ajaxSetup({
async: false
});
// Your $.getJSON() request is now synchronous...
// Set the global configs back to asynchronous
$.ajaxSetup({
async: true
});
Asynchronusly does mean the Request is running in the background, and calls your function back when it got a response. This method is best if you want to have a result but allow to use your app within the request. If you want to have a direct response, take a look at a synchron request. this request will pause script execution until it got a response, and the user can not do anything until the response was recieved. You can toggle it via:
async: false,
So for example:
$.ajax({
url: "myurl",
async: false,
...
})
$.getJSON(), doesn't accept a configuration, as it says in the docs it's a shorthand version of:
$.ajax({
dataType: "json",
url: url,
data: data,
success: success
});
So just rewrite your request in terms of that and async:false will work just as you expect.
$.getJSON() is a shorthand notation for $.ajax() which can be configured to be synchronous (see jQuery.getJSON and JQuery.ajax):
$.ajax({
dataType: "json",
url: url,
data: data,
async: false,
success: function(data) {
...
draw_polygon(data);
}
});
Try to avoid synchronous calls though. Quote from jQuery doc (see async prop):
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.
You might want to try jQuery Deferreds like this:
var jqxhr = $.getJSON(url);
jqxhr.done(function(data) {
...
draw_polygon(data);
});

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

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);
}

How to block execution of function untill json return result?

I am using Springer OpenAccess API with JS, they provide their data with many ways, one of them is jsonp format. My code is shown below. What ever i do, i couldn't make it run synchronuously. Callback mechanism is good solution but i want to learn how to run this function syncronously or how enable this function to behave syncronous.
Any help will be appreciated.
SpringerAPI.prototype.getArticleInfo = function(doi){
//create url of article according to given doi...
var url = this.endpoint.host+this.endpoint.method+''+'?q=doi:'+doi+'&api_key='+this.endpoint.apikey+"&callback=?";
//get information about article...
//perform async request to the Springer API
this.situation = true;
var article;
jQuery.ajax({
method:'POST',
url: url,
dataType: 'JSON',
cache: true,
async: false, // to set local variable
success: function(data)
{
article = FromSpringerToArticle(data,-1);
}
});
return article;
};
You can't do synchronous JSONP because jQuery doc says
async
...
Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation...
You'll have to do an asyc operation and use callbacks.

Categories