I do a bunch of json requests with dynamic script tags. Is it possible to detect if there's an error in the request (eg. 503 error, 404 error) and run something on detection of the error?
views:
597answers:
7AFAIK, there's no way to access status code of some external asset loaded from the document (such as script, style or image). Even detecting error (via, say, onerror
event handler) is not that widely supported across browsers.
If whatever you're loading falls under SOP, use XHR which gives you access to response headers. Otherwise, you can try looking into recently introduced X-domain XHR.
use ajax instead. AFAIK there is no way to detect if a script tag loads or not, and if not, why it didn't load. Using ajax you can load the json and it will tell you why it didn't load.
Using a library like jQuery this becomes very simple:
$.ajax({
type: "GET",
url: "test.js",
dataType: "script",
error: function(xhr, error, exception){
alert(xhr.status); //Will alert 404 if the script does not exist
}
});
If you want to detect errors, listen for an error
event and compare the fileName
property of the error with the file name of the script. If they match, you then handle the error. The thing is, I think that the fileName
property is Firefox and Opera-only. Most browsers that have a stacktrace for errors can also simulate this behaviour.
Here's an example, as requested by Eric Bréchemier:
var getErrorScriptNode = (function () {
var getErrorSource = function (error) {
var loc, replacer = function (stack, matchedLoc) {
loc = matchedLoc;
};
if ("fileName" in error) {
loc = error.fileName;
} else if ("stacktrace" in error) { // Opera
error.stacktrace.replace(/Line \d+ of .+ script (.*)/gm, replacer);
} else if ("stack" in error) { // WebKit
error.stack.replace(/at (.*)/gm, replacer);
loc = loc.replace(/:\d+:\d+$/, "");
}
return loc;
},
anchor = document.createElement("a");
return function (error) {
anchor.href = getErrorSource(error);
var src = anchor.href,
scripts = document.getElementsByTagName("script");
anchor.removeAttribute("href");
for (var i = 0, l = scripts.length; i < l; i++) {
anchor.href = scripts.item(i).src;
if (anchor.href === src) {
anchor.removeAttribute("href");
return scripts.item(i);
}
}
};
}());
I'm assuming you want this to work cross-domain, which is why you can't use XHR?
Try creating two script tags for each request, the first does your standard JSONP request, the second is basically an error handler.
If the first script tag executes, then clear the error handler in your callback. But if the first gets a 404, the error handler inside the second script tag will be run.
You probably also want to set a timeout, to cope with a slow JSONP response.
If you need to cross domains (and need the page to work portably), you have to use dynamic script tags.
If you have access to the remote server, you can pass back an error code from the server, and have the server page return 200.
Whether you have access or not, you can use setTimeout when you create the script tag, passing a function that will trigger an error if it expires before the jsonp handler is called. Make sure that the jsonp handler aborts if the error handler has been called.
You'll need to track each request through a global collection, but you'll gain the ability to cancel and count requests. This is similar to the way that XHR objects are managed by a library like jQuery.
If you're using jQuery, check out jQuery-JSONP which is a jQuery plugin that does a fairly decent job of doing the <script>
insertion for you as well as detecting fetch errors.
Quoting from the project page, jQuery-JSONP features:
- error recovery in case of network failure or ill-formed JSON responses,
- precise control over callback naming and how it is transmitted in the URL,
- multiple requests with the same callback name running concurrently,
- two caching mechanisms (browser-based and page based),
- the possibility to manually abort the request just like any other AJAX request,
- a timeout mechanism.