How can I do a synchronous request with jQuery? - javascript

Why don't return that function the responseText?
function LoadBookmarksAsXml()
{
return $.ajax(
{
type: 'GET',
async: false,
url: 'http://www.google.com/bookmarks/?output=xml&num=10000'
}).responseText;
}
(It works if I define a success-callback-function and set async to true!)
Thanks in advance!!
Edit: Don't worry about the cross-domain call; user603003 says (in a comment on a now-deleted answer) that this is in a Chrome extension where cross-domain requests are allowed.
The solution if someone wants to do the same:
return $.ajax(
{
type: 'GET',
async: false,
url: 'http://www.google.com/bookmarks/?output=xml&num=10000',
});
(You will get a XMLHTTPRequest object.)

I'm not immediately seeing why it's not returning it, but I'd still use a success callback:
function LoadBookmarksAsXml()
{
var result;
$.ajax(
{
type: 'GET',
async: false,
url: 'http://www.google.com/bookmarks/?output=xml&num=10000',
success: function(data) {
result = data;
}
});
return result;
}
Even though $.ajax returns an XMLHttpRequest object (in 1.4 or earlier) or a jqXHR object (in 1.5+), I'd still prefer using a success function and an error function for clarity. Also, different versions of jQuery give you different values for responseText on error (at least on Chrome; 1.4.4 returns an empty string, 1.5.0 returns undefined).
If there's any way you can avoid it, avoid it. Synchronous requests completely lock up the UI of most browsers (not just your page's UI, every page in every tab that browser is managing). Since ajax requests can take a second or two (or five, or ten), this makes for a very unpleasant user experience. Nearly all the time, you can avoid it by refactoring your function so it accepts a callback to use to supply the result:
function LoadBookmarksAsXml(callback)
{
$.ajax(
{
type: 'GET',
url: 'http://www.google.com/bookmarks/?output=xml&num=10000',
success: function(data) {
callback(data);
},
error: function() {
callback(null);
}
});
}
Off-topic: I'll be surprised if the request works at all, though, because on the face of it (unless you work for Google), that request will fail because of the Same Origin Policy. Various ways to get around the SOP:
JSONP
CORS (but it requires browser support and that www.google.com allow the request from your origin)
Using YQL as a proxy

$.ajax never returns the response text, it always returns the XMLHTTPRequest object created to make the Ajax call.
You'll still need to define a success callback I think, e.g. one setting a local variable which you can then return.
Standard disclaimer: Synchronous requests are a usually discouraged practice because they can freeze the current page.

Waiting for the response of a function is not asyncronous, the ajax call will have a response when it is done, you have to take care of the response then, by defining callbacks for the successful event.
You have ti break up your code to at least two parts. First part is before the ajax call, second part is after the success, and put everything you want to do with the requested data in the success callback. Asyncronous requests work this way.

Doing that is a really bad idea. Javascript will block for the duration of the HTTP request, which is to say nothing else in the UI thread will run until the ajax call returns. Use a callback.

By design, asynchronous requests can't deliver a responseText out of the blue ;-)
You HAVE to set a callback function and decide how you will handle the responseText.

Related

JavaScript ajax, JSONP, Callback function to do something with data

Fellas,
I'm trying to do an ajax call to get some JSON. I can get around the cross origin issues in Chrome very easily but in IE the only way I got it working without throwing an error is using JSONP. My problem is that i don't know how to process the response. I can see that the call executes and it returns JSON in fiddler but how do i catch it and play with it in my code that's below.
$.support.cors = true;
function callAjaxIE(){
$.ajax({
type: 'GET',
async: true,
url: usageUrl,
dataType: 'jsonp',
crossDomain: true,
jsonp: false,
jsonpCallback: processDataIE,
// cache: false,
success: function (data) {
alert('success');
//processData(data)
},
error: function (e){
console.log(e);
}
}).done(function (data) {
alert('done');
});
function processDataIE(){
alert('processing data ie');
}
It works when i run it, it displays a message box saying 'processing data ie' but so what. How do i play with the results?
UPDATE:
So I've updated the code as per Quentin. It doesn't go into the 'success' block. It errors out with the following.
When i look at fiddler. The JSON is there. How do i get it?
Don't force the function name. That's a recipe for race conditions. Remove jsonpCallback: processDataIE. Let jQuery determine the function name.
Don't remove the callback parameter from the URL. Make the server read callback from the query string to determine which function to call. Remove jsonp: false,.
Use the success function as normal. (Get rid of processDataIE, that's what success is for).
Asides:
crossDomain: true is pointless. It tells jQuery that when it is using XHR (which you aren't) and the URL is pointing to the same origin (which it isn't) then it should not add extra headers in case the server does an HTTP redirect to a different origin.
async: true is pointless. That's the default, and JSONP requests can't be anything other than async anyway.
$.support.cors = true; is pointless at best and can be harmful. Remove it.
Don't override jQuery's detection of support for CORS by the browser. You can't make ancient browsers support CORS by lying to jQuery. You're using JSONP anyway, so CORS is irrelevant.
The above is the sensible, standard, robust solution.
If you want the quick hack that maintains all the bad practises you have in play, then just look at the first argument to processDataIE.

jQuery $.when().done() not working as expected with JSONP when loading a local .json file

I'm building an SPA using Sammy and Knockout powered by a REST Web Service available on a different URL.
I'm noticing some odd behavior when returning JSONP versus JSON when using $.when().done()...
.done() never fires, but .fail() will, even though the status code I receive is 200, and JSONP Linter tells me that my JSONP is valid:
(function($) {
$(function() {
$.when($.getJSON('endpoint1?callback=?', null),
$,getJSON('endpoint2?callback=?', null))
.done(function(resp1, resp2) {
console.log(resp1); // this is never called
});
})
.fail(function(obj) {
console.log(obj); // this is called, but why?
});
});
})(jQuery);
A sample response returned is:
callback({
"external-links": [
{
"nav_link_text": "Stack Overflow",
"url": "http://stackoverflow.com"
}
]
});
If I return JSON instead of JSONP, .done() works as expected. What am I doing wrong or need to change?
The problem is specified here:
ReferenceError: callback is not defined
Your JSONP response has callback hard-coded. That's incorrect. JSONP needs to set the function name dynamically.
When jQuery sends a JSONP request, it creates a function called jQuery123456 (or something like that) and sends that name in the request. It calls endpoint1?callback=jQuery123456. The job of JSONP is to make a call to that function. Your JSONP needs to return:
jQuery123456({
your: 'data'
})
You need to use the value of the callback parameter.
If for some reason, creating the JSONP "dynamically" isn't an option, you can force jQuery to name the callback function it creates. You need to use $.ajax for this:
$.ajax({
url: 'endpoint1',
dataType: 'jsonp',
jsonp: false, // Don't add the "?callback=?" param,
// you're not using it anyway
jsonpCallback: 'callback' // Force jQuery to use "callback"
// as the function name
});
Note: jQuery probably won't like having the same callback value for multiple requests.

What/when does a call to the jQuery AJAX method return?

A little background:
I am trying to implement and AJAX powered SlickGrid. There isn't much documentation so I used this example as a base.
In this example there is the following code that hits the desired web service to get the data:
req = $.jsonp({
url: url,
callbackParameter: "callback",
cache: true, // Digg doesn't accept the autogenerated cachebuster param
success: onSuccess,
error: function(){
onError(fromPage, toPage)
}
});
req.fromPage = fromPage;
req.toPage = toPage;
I'm not exactly sure what jsonp does but from what i've read it appears to be very similar to the ajax method in jQuery except it returns json and allows cross domain requests. The webservice that I happen to be calling only returns XML so I changed this chunk of code to:
req = $.ajax({
url: "/_vti_bin/lists.asmx",
type: "POST",
dataType: "xml",
data: xmlData,
complete: onSuccess,
error: function (xhr, ajaxOptions, thrownError) {
alert("error: " + xhr.statusText);
alert(thrownError);
},
contentType: "text/xml; charset=\"utf-8\""
});
req.fromPage = fromPage;
req.toPage = toPage;
My issue is that my page errors out at req.fromPage = fromPage; because req is null.
Am I wrong to think that I can just replace my jsonp call with a call to the ajax method? Is req just not set because my ajax call hasn't finished by the time that code is executed? How can I get around either of these issues?
If I comment out the last two lines and hard-code those values elsewhere everything runs fine.
Am I wrong to think that I can just replace my jsonp call with a call to the ajax method?
No, that should work just fine.
Is req just not set because my ajax call hasn't finished by the time that code is executed?
Yes, that is correct.
The ajax methods starts the request and returns immediately. If you want to do something after the response has arrived you should do that in the success event handler.
You might actually want to use the success event instead of the complete event, as the complete event happens even if there is an error.
You could specify async: false, in your settings to make the ajax call wait for the response, but that means that the browser freezes while it's waiting.
As Guffa stated, $.ajax() works asynchronically. Thus, you have to specify a callback that will be called when the request has returned a response, rather than to just use whatever $.ajax() returns.
There are a couple of different callback methods you can specify:
complete - runs when you recieve a response, regardless of its status.
success - runs when you recieve a response with a successful status code (usually 200).
error - runs when you recieve a response with an error code (for example 404 or 500).
To do something with the response body after a successful request, you should do something like
$.ajax({
...
success: function(body) {
alert('This is the method body:' + body);
}
});
Read up in the documentation on the different methods to see what more parameters you can use.

Javascript Synchronization with JSON Requests

How can I make sure that a piece of code has executed completely before executing another? I am sending some ajax requests to a server and then using the returned data to generate the rest of the webpage. the things is, is that i need to have all that data in the webpage to proceed with the rest of the code as that code will affect what has been generated and, that code, runs before the json requests and all of that have finished... is there any way I can make sure this does not happen? I managed to solve it by performing the requests and then asking the user to press a button but that is a total no-sense way of doing it.
Any ideas?
Here is some code: The problem is that the second line is executed before the first (there are many calls to similar JSON functions).
$.getJSON(url, function(data){ $("#mycontent").append("..... stuff here...... create loads of dibs with class set to mydivclass"); });
...
$("div.mydivclass").hide();
Unforunately I cannot use the ajax synchronous property because: "dataType: "jsonp" requests do not support synchronous operations"
If you are using jQuery 1.5+ you can make use of deferreds to solve your issue:
function first_ajax_request() {
return jQuery.ajax(
// Your settings here
success: success_function_1
);
}
function second_ajax_request() {
return jQuery.ajax(
// Your settings here
success: success_function_2
);
}
function final_sucess_callback() {
// Do all your display work.
}
jQuery.when(first_ajax_request(),
second_ajax_request()).then(final_success_callback);
There is an excellent article on the topic that you should read up on as well by Eric Hynds. He gives some examples of exactly the kind of problem you are trying to solve.
jquery requests are asynchonize by default , so your code does not wait for the response , so you have no guarantee that code after request will execute after the response , so you can set the request synchronize by set the async property false , now the request is synchronize and you can gurantee the rest of the code will execute after the response from the server ,
like this .
$.ajax({
url: "page.php",
processData: false,
data: xmlDocument,,
async:false,
success: handleResponse
});

Catching a JSONP error on a cross-domain request

I'm using jQuery.getJSON() on a URL (different domain) which may not exist. Is there a way for me to catch the error "Failed to load resource"? It seems that try/catch doesn't work because of the asynchronous nature of this call.
I can't use jQuery.ajax()'s "error:" either. From the documetation:
Note: This handler is not called for cross-domain script and JSONP requests.
If you have an idea of the worst case delay of a successful result returning from the remote service, you can use a timeout mechanism to determine if there was an error or not.
var cbSuccess = false;
$.ajax({
url: 'http://example.com/.../service.php?callback=?',
type: 'get',
dataType: 'json',
success: function(data) {
cbSuccess = true;
}
});
setTimeout(function(){
if(!cbSuccess) { alert("failed"); }
}, 2000); // assuming 2sec is the max wait time for results
This works:
j.ajaxSetup({
"error":function(xhr, ajaxOptions, thrownError) {
console.log(thrownError);
}});
Deferred objects (new in jQuery 1.5) sound like exactly what you're looking for:
jQuery.Deferred, introduced in version 1.5, is a chainable utility object that can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.
http://api.jquery.com/category/deferred-object/
EDIT:
The following code works fine for me:
function jsonError(){
$("#test").text("error");
}
$.getJSON("json.php",function(data){
$("#test").text(data.a);
}).fail(jsonError);
json.php looks like this:
print '{"a":"1"}';
The error function fires for me if the path to json.php is incorrect or if the JSON is malformed. For example:
print '{xxx"a":"1"}';
What your complaining about is a client-side error saying that you tried to download a resource from the server.
This is build into the browser and it allows your browser to tell the client or the developers that the downloading of a resource from the internet failed. This has nothing to do with JavaScript and is a more low level error thrown on the HTTP that is caught by the browser.
If you want any hope of catching it your going to need to drop 3rd party ajax libraries and deal with the XMLHTTPRequest object on a much lower level, even then I doubt you can do anything about it.
Basically when you see this error then find out what object your trying to get that doesn't exist or couldn't be accessed. Then either stop accessing it or make it accessible.

Categories