When I make a synchronous jQuery ajax request, I need the ability to delay displaying the error message to the user until I can add some more information that does not exist in the context of my error function. I'm trying to find a way to throw the information collected about the exception so that it can be caught higher up the chain and and be displayed with more meaningful information to the user. I'm finding that even with synchronous requests, when I put a throw statement inside my error function that it is not caught by my wrapping catch block.
function GetFileName(entity, field, guid){
var filename;
try
{
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
datatype: "json",
url: myURLwashere,
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("Accept", "application/json");
},
async: false,
success: function (data, textStatus, xhr) {
var result = data.d;
filename = result[field];
},
error: function (xhr, textStatus, errorThrown) {
throw textStatus + " " + errorThrown;
//entity, field and guid are null here
}
});
}
catch (err){
//this catch block does not catch the exception thrown by the error function.
throw "Error Getting File Name from web service for entity '" + entity + "' field '" + field + "' and guid '" + guid + "' (" + err.message + ")";
}
return filename;
}
This is a very simple example. I could be nested through several functions several layers deep and want to add to the error message multiple times before displaying it to the user.
Update
I've updated the question to reflect my end-goal (nested error handling) without requiring that the solution be synchronous, which has been discouraged.
I'm writing this in response to the Troy's question in the comments, "How about some recommendations for how to properly aggregate good error messages in nested calls with an asynchronous request instead?"
If you've not done much event-driven (asynchronous) programming before, it does take a little getting used to. Find yourself a good online tutorial like this one:http://code.tutsplus.com/tutorials/event-based-programming-what-async-has-over-sync--net-30027. If you're just starting out you might want to avoid getting into the Deferred or Promise model of asynchronous programming. Those are great tools, but callbacks are an easier way to start out.
One way to transform your code to be asynchronous is to give your function two extra "callback function" parameters:
function GetFileName(entity, field, guid, onSuccess, onError){
Now change async to true and modify the success and errors functions like this:
async: true,
success: function (data, textStatus, xhr) {
var result = data.d;
filename = result[field];
onSuccess( filename );
},
error: function (xhr, textStatus, errorThrown) {
// REMOVE: throw textStatus + " " + errorThrown;
//entity, field and guid are null here
onError(textStatus, errorThrown);
}
Then remove the catch block and the return statement.
This style will cause you to rework or maybe even redesign some of your current code base. But as others have pointed out, using synchronous ajax calls can create a really poor user experience.
Related
Is it possible to catch an error when using JSONP with jQuery? I've tried both the $.getJSON and $.ajax methods but neither will catch the 404 error I'm testing. Here is what I've tried (keep in mind that these all work successfully, but I want to handle the case when it fails):
jQuery.ajax({
type: "GET",
url: handlerURL,
dataType: "jsonp",
success: function(results){
alert("Success!");
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("Error");
}
});
And also:
jQuery.getJSON(handlerURL + "&callback=?",
function(jsonResult){
alert("Success!");
});
I've also tried adding the $.ajaxError but that didn't work either:
jQuery(document).ajaxError(function(event, request, settings){
alert("Error");
});
Here's my extensive answer to a similar question.
Here's the code:
jQuery.getJSON(handlerURL + "&callback=?",
function(jsonResult){
alert("Success!");
})
.done(function() { alert('getJSON request succeeded!'); })
.fail(function(jqXHR, textStatus, errorThrown) { alert('getJSON request failed! ' + textStatus); })
.always(function() { alert('getJSON request ended!'); });
It seems that JSONP requests that don't return a successful result never trigger any event, success or failure, and for better or worse that's apparently by design.
After searching their bug tracker, there's a patch which may be a possible solution using a timeout callback. See bug report #3442. If you can't capture the error, you can at least timeout after waiting a reasonable amount of time for success.
Detecting JSONP problems
If you don't want to download a dependency, you can detect the error state yourself. It's easy.
You will only be able to detect JSONP errors by using some sort of timeout. If there's no valid response in a certain time, then assume an error. The error could be basically anything, though.
Here's a simple way to go about checking for errors. Just use a success flag:
var success = false;
$.getJSON(url, function(json) {
success = true;
// ... whatever else your callback needs to do ...
});
// Set a 5-second (or however long you want) timeout to check for errors
setTimeout(function() {
if (!success)
{
// Handle error accordingly
alert("Houston, we have a problem.");
}
}, 5000);
As thedawnrider mentioned in comments, you could also use clearTimeout instead:
var errorTimeout = setTimeout(function() {
if (!success)
{
// Handle error accordingly
alert("Houston, we have a problem.");
}
}, 5000);
$.getJSON(url, function(json) {
clearTimeout(errorTimeout);
// ... whatever else your callback needs to do ...
});
Why? Read on...
Here's how JSONP works in a nutshell:
JSONP doesn't use XMLHttpRequest like regular AJAX requests. Instead, it injects a <script> tag into the page, where the "src" attribute is the URL of the request. The content of the response is wrapped in a Javascript function which is then executed when downloaded.
For example.
JSONP request: https://api.site.com/endpoint?this=that&callback=myFunc
Javascript will inject this script tag into the DOM:
<script src="https://api.site.com/endpoint?this=that&callback=myFunc"></script>
What happens when a <script> tag is added to the DOM? Obviously, it gets executed.
So suppose the response to this query yielded a JSON result like:
{"answer":42}
To the browser, that's the same thing as a script's source, so it gets executed. But what happens when you execute this:
<script>{"answer":42}</script>
Well, nothing. It's just an object. It doesn't get stored, saved, and nothing happens.
This is why JSONP requests wrap their results in a function. The server, which must support JSONP serialization, sees the callback parameter you specified, and returns this instead:
myFunc({"answer":42})
Then this gets executed instead:
<script>myFunc({"answer":42})</script>
... which is much more useful. Somewhere in your code is, in this case, a global function called myFunc:
myFunc(data)
{
alert("The answer to life, the universe, and everything is: " + data.answer);
}
That's it. That's the "magic" of JSONP. Then to build in a timeout check is very simple, like shown above. Make the request and immediately after, start a timeout. After X seconds, if your flag still hasn't been set, then the request timed out.
I know this question is a little old but I didn't see an answer that gives a simple solution to the problem so I figured I would share my 'simple' solution.
$.getJSON("example.json", function() {
console.log( "success" );
}).fail(function() {
console.log( "error" );
});
We can simply use the .fail() callback to check to see if an error occurred.
Hope this helps :)
If you collaborate with the provider, you could send another query string parameter being the function to callback when there's an error.
?callback=?&error=?
This is called JSONPE but it's not at all a defacto standard.
The provider then passes information to the error function to help you diagnose.
Doesn't help with comm errors though - jQuery would have to be updated to also callback the error function on timeout, as in Adam Bellaire's answer.
Seems like this is working now:
jQuery(document).ajaxError(function(event, request, settings){
alert("Error");
});
I use this to catch an JSON error
try {
$.getJSON(ajaxURL,callback).ajaxError();
} catch(err) {
alert("wow");
alert("Error : "+ err);
}
Edit: Alternatively you can get the error message also. This will let you know what the error is exactly. Try following syntax in catch block
alert("Error : " + err);
Mayby this works?
.complete(function(response, status) {
if (response.status == "404")
alert("404 Error");
else{
//Do something
}
if(status == "error")
alert("Error");
else{
//Do something
}
});
I dont know whenever the status goes in "error" mode. But i tested it with 404 and it responded
you ca explicitly handle any error number by adding this attribute in the ajax request:
statusCode: {
404: function() {
alert("page not found");
}
}
so, your code should be like this:
jQuery.ajax({
type: "GET",
statusCode: {
404: function() {
alert("page not found");
}
},
url: handlerURL,
dataType: "jsonp",
success: function(results){
alert("Success!");
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("Error");
}
});
hope this helps you :)
I also posted this answer in stackoverflow - Error handling in getJSON calls
I know it's been a while since someone answerd here and the poster probably already got his answer either from here or from somewhere else. I do however think that this post will help anyone looking for a way to keep track of errors and timeouts while doing getJSON requests. Therefore below my answer to the question
The getJSON structure is as follows (found on http://api.jqueri.com):
$(selector).getJSON(url,data,success(data,status,xhr))
most people implement that using
$.getJSON(url, datatosend, function(data){
//do something with the data
});
where they use the url var to provide a link to the JSON data, the datatosend as a place to add the "?callback=?" and other variables that have to be send to get the correct JSON data returned, and the success funcion as a function for processing the data.
You can however add the status and xhr variables in your success function. The status variable contains one of the following strings : "success", "notmodified", "error", "timeout", or "parsererror", and the xhr variable contains the returned XMLHttpRequest object
(found on w3schools)
$.getJSON(url, datatosend, function(data, status, xhr){
if (status == "success"){
//do something with the data
}else if (status == "timeout"){
alert("Something is wrong with the connection");
}else if (status == "error" || status == "parsererror" ){
alert("An error occured");
}else{
alert("datatosend did not change");
}
});
This way it is easy to keep track of timeouts and errors without having to implement a custom timeout tracker that is started once a request is done.
Hope this helps someone still looking for an answer to this question.
I am working on below Ajax code in JavaScript, I am trying to pop up a dialog box when the URL could not load the JSON properly the reason may be either expired token or incorrect token, in any case, I am expecting the code to hit the error or fail but it's not happening. When the URL could load the JSON successfully, success and complete blocks are being hit as expected but nothing is being hit when URL fails. I have tried to use async: false and tried to check with a boolean variable weHaveSuccess but console.log(weHaveSuccess); which is in the last line of the code is getting executing even before success/error is being executed and it seems to me like its still loading asynchronously. I would like to know why error block is not being hit when the JSON load from URL is getting failed.
My code
function checkUser(myURL, newAccessToken, weHaveSuccess) {
$.ajax({
type: "GET",
dataType: "jsonp",
async: false,
url: myURL + newAccessToken,
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log("Status: " + textStatus);
console.log("Error: " + errorThrown);
},
success: function (data) {
console.log("Hello 2 " + JSON.stringify(data));
weHaveSuccess = true;
console.log('Message from Success ' + weHaveSuccess);
},
complete: function () {
console.log('Message from Complete ' + weHaveSuccess);
}
}).done(function (data) {
alert("Success");
console.log(data);
}).fail(function (data) {
console.log(data);
alert("Failed");
}).always(function () {
alert("In Always");
});
console.log(weHaveSuccess);
}
Thanks in advance!
AJAX requests are asynchronous. It takes time for a remote request to be made and responded to. You will have to write your post-response code within the success function or call another function from there, not within the same scope as where the call is initiated.
I am taking a bit of a guess here about what your server returns on failure. An AJAX request success means simply that a 200 OK response was received, without any consideration of the contents of the data. If an error is simply a change in the data you will need do one of the following to show an error:
Have the server set a status code header on failure, perhaps 400 Bad Request.
In the success function look within your data for whatever error response you are expecting and trigger the alert() there.
First of all the console.log(weHaveSuccess); fires first, because the $.ajax() is asynchronous while console.log is not so ajax will be triggered and return the promise when finishes, but the browser will continue with the script.
In the jQuery ajax docs says:
Cross-domain requests and dataType: "jsonp" requests do not support
synchronous operation.
It's hard to debug without seeing the response, maybe you can add some info from the network or a URL?
How about if you try the following:
Add the jsonp setting to your $.ajax() function for the callback that will handle the response and console.log there:
function myCallback(data) {
console.log(data);
}
$.ajax({
type: "GET",
dataType: "jsonp",
jsonp: myCallback,
...
I have been trying all the methods that i have seen in the stack overflow asked by other users before.But none of them are working.Please hoping any of you would point me in the right direction
$.ajax({
type: "get",
dataType:'jsonp',
params:jsonData,
jsonp:false,
jsonpCallback:"callbackfn",
headers: { "api_key": "u5FocU4xLq2rBfZ1ZSV8o81R2usYzUEM3NaCinnV"},
url: "http://localhost/url?name=xxx&email=xxxxxx#gmail.com",
success:function(){
alert("sucess function");
},
error: function(jqXHR, textStatus, errorThrown){
alert(textStatus + " and<br> " + errorThrown);
}
});
function callbackfn(data) {
alert(data);
}
the response is {
"firstName":"John",
"lastName":"Doe"
}
Although the response is json,this rises an error
Parse error .callbackfn not called.
In order to use a custom callback function with JSONP, you must declare its scope to be global, i.e.
window.callbackfn = function(data) {
alert(data);
};
Why?
This is because successful JSONP responses return a new JavaScript file, that is, a JavaScript function call encapsulated in <script> tags. Since each script is independently evaluated in the global scope, any script's function you would like to be made available to another script must also be declared in the global scope. Thus all JSONP callback functions should be global.
EDIT
According to OP, the solution found here: Return JSONP via AWS Lambda/API Gateway did the trick. Issue had to do with an improper server-side JSONP response.
Make sure that your response from the server is a function call with the response data as the argument. It appears you are just outputting JSON, but JSONP expects a function call with the response data. Your server response should look like this:
callbackfn({
"firstName":"John",
"lastName":"Doe"
});
You have jsonp: false with a jsonpCallback and dataType: 'jsonp' - which is odd, because you are also supplying a jsonp callback. Perhaps if you don't need JSONP due to cross-origin requests, you should remove the jsonpCallback argument and just manually call that function with the response:
$.ajax({
type: "get",
dataType:'json',
params:jsonData,
headers: { "api_key": "u5FocU4xLq2rBfZ1ZSV8o81R2usYzUEM3NaCinnV"},
url: "http://localhost/url?name=xxx&email=xxxxxx#gmail.com",
success:function(data){
callbackfn(data);
},
error: function(jqXHR, textStatus, errorThrown){
alert(textStatus + " and<br> " + errorThrown);
}
});
I a javascript function which sends an ajax request. Note that the server might return an error even if "everything seems to be ok" which means that there might be an error information in the handler of success:
function sendAjaxRequest(){
$.ajax({
type: "GET",
url: "/123",
success: function(data){
//there might and might not an error in data
if(data.error_exists){
retryIfError(data);
} else{
//everything is ok for sure
}
},
error: function(xhr, textStatus, errorThrown){
//there is the error for sure
retryIfError(xhr);
}
});
}
function retryIfError(data){
var error = data.error_list # the array of error messages
// ... what should I do further?
}
The reason is that success: function(data) might have an error is that the server uses begin ... rescue operators to suppress them. Is that the right approach?
The second question:
So the goal is to send sendAjaxRequest() until there are no errors anymore. How do I do that? Of course, I want also restrict the amount of sending sendAjaxRequest() requests, but I think it will be trivial and I'll take care of it by myself.
What about calling the function again? you can add a counter as well.
error: function(xhr, textStatus, errorThrown){
if(i<3)
sendAjaxRequest(i++);
}
And use.
var i=0;
I am using jQuery 1.6 and I would like to know and understand how I can access response xhr, status and ex variables in the following code:
$jQuery.ajax({
type: "POST",
url: "<some_url>",
error: function(xhr, status, ex) {
var msg = "";
if (xhr) {
msg = "readyState is " + xhr.readyState + ". ";
}
if (ex) {
msg += ex.name + ' - ' + ex.message;
}
alert("ERROR " + msg); }
success: function(jqXHR, status, ex) {
...
}
});
How can I know the full list of all them "accessible" values like, for example, readyState for the xhr (xhr.readyState), name and message for the ex (ex.name and ex.message)?
Moreover, what xhr and ex variables represent (I think status refers to the HTTP status code)?
I strongly suggest you to have a look at the docs.
Here an example.
error(jqXHR, textStatus, errorThrown)Function
A function to be called if the request fails. The function receives three arguments: The jqXHR (in jQuery 1.4.x, XMLHttpRequest) object, a string describing the type of error that occurred and an optional exception object, if one occurred. Possible values for the second argument (besides null) are "timeout", "error", "abort", and "parsererror". When an HTTP error occurs, errorThrown receives the textual portion of the HTTP status, such as "Not Found" or "Internal Server Error." As of jQuery 1.5, the error setting can accept an array of functions. Each function will be called in turn. Note: Prior to jQuery 1.5, this handler was not called for cross-domain script and JSONP requests. This is an Ajax Event
jQuery has a very good documentation. The docs should be the first place to look at, for questions like yours. If you encounter problems while implementing jQuery you are welcome to ask at SO.