AJAX error handling
Many pages send AJAX requests to a server. Because this relies on the cooperation of the server and the network between the client and the server, you can expect these AJAX errors:
- Your JavaScript program receives an error response instead of data;
- Your program has to wait too long for the response. You can't have the user wait indefinitely for some data to load.
- Your program has to wait longer than expected for the response. You or your marketing department may decide to time out after 5 seconds, and that if responses take over 2 seconds to arrive you want to know about it.
This page shows how to implement AJAX error handling with JavaScript loggers that log to the server, so you find out about these issues.
Initial code without proper AJAX error handling
Below is a fairly typical AJAX call implemented with jQuery's $.ajax:
var requestData = data to send to server; var url = Url to send request to; // Show spinner image
$.ajax(url, { "data": requestData, "type": "POST" }) .done(function (data, textStatus, jqXHR) { // Process data, as received in data parameter }) .fail(function (jqXHR, textStatus, errorThrown) { // Request failed. Show error message to user. // errorThrown has error message. }) .always(function(jqXHR, textStatus, errorThrown) { // Hide spinner image }
Step 1: Add timeout
The $.ajax method lets you set a timeout in milli seconds. When a timeout happens,
- The fail callback is called, with errorThrown set to "timeout".
- The request is aborted, meaning that even if the response arrives later on, your done callback is not called by jQuery.
var requestData = data to send to server; var url = Url to send request to;
// Show spinner image
$.ajax(url, { "data": requestData, "type": "POST", "timeout": 5000 }) .done(function (data, textStatus, jqXHR) { // Process data, as received in data parameter }) .fail(function (jqXHR, textStatus, errorThrown) { // Request failed. Show error message to user. // errorThrown has error message, or "timeout" in case of timeout. }) .always(function(jqXHR, textStatus, errorThrown) { // Hide spinner image }
Step 2: Log fatal message in case of error or timeout
When there is an AJAX error response or the AJAX request times out, you'll want to log as much information as you have, including the error message that jQuery gives you, the url and the request data.
var requestData = data to send to server; var url = Url to send request to; // Show spinner image
$.ajax(url, { "data": requestData, "type": "POST", "timeout": 5000 }) .done(function (data, textStatus, jqXHR) { // Process data, as received in data parameter }) .fail(function (jqXHR, textStatus, errorThrown) { // Request failed. Show error message to user. // errorThrown has error message, or "timeout" in case of timeout.
JL().fatal({ "msg": "AJAX error response", "errorThrown": errorThrown, "url": url, "requestData": requestData }); }) .always(function(jqXHR, textStatus, errorThrown) { // Hide spinner image }
Step 3: Log warning message if AJAX response takes longer than expected
Record the time before making the AJAX call and compare that with the time when the response is received to find out how long the user had to wait for the response. Log a warning message if it took longer than expected.
var requestData = data to send to server; var url = Url to send request to; // Show spinner image var msBeforeAjaxCall = new Date().getTime();
$.ajax(url, { "data": requestData, "type": "POST", "timeout": 5000 }) .done(function (data, textStatus, jqXHR) { // Process data, as received in data parameter
// Send warning log message if response took longer than 2 seconds var msAfterAjaxCall = new Date().getTime(); var timeTakenInMs = msAfterAjaxCall - msBeforeAjaxCall; if (timeTakenInMs > 2000) { JL().warn({ "msg": "AJAX response took long time", "timeTakenInMs": timeTakenInMs, "url": url, "data": data, "requestData": requestData }); } }) .fail(function (jqXHR, textStatus, errorThrown) { // Request failed. Show error message to user. // errorThrown has error message, or "timeout" in case of timeout.
JL().fatal({ "msg": "AJAX error response", "errorThrown": errorThrown, "url": url, "requestData": requestData }); }) .always(function(jqXHR, textStatus, errorThrown) { // Hide spinner image }