JavaScript AJAX Response

When an AJAX request completes, the server sends back a response. The XMLHttpRequest object provides properties and events to access the response data, check the status, and handle errors.

responseText and responseXML

The responseText property returns the response as a string. The responseXML property returns the response as an XML document (if the response is XML). For JSON data, use JSON.parse() on responseText.

Reading Response Data
// After a successful request:
// xhr.responseText - response as string
// xhr.responseXML  - response as XML document

// Simulating responseText (JSON string from server)
const responseText = '{"name": "Alice", "age": 30, "city": "NYC"}';

// Parse JSON response
const data = JSON.parse(responseText);
console.log('Name: ' + data.name);
console.log('Age: ' + data.age);
console.log('City: ' + data.city);

// For plain text responses
const textResponse = 'Hello, World!';
console.log('Text response: ' + textResponse);

HTTP Status Codes

The status property contains the HTTP status code returned by the server. The statusText property provides a brief description.

Status CodeMeaningDescription
200OKRequest succeeded
201CreatedResource created (POST)
204No ContentSuccess, no response body
301Moved PermanentlyResource URL changed
400Bad RequestInvalid request syntax
401UnauthorizedAuthentication required
403ForbiddenAccess denied
404Not FoundResource does not exist
500Internal Server ErrorServer-side error
Checking Status Codes
// Simulating status checking
function handleResponse(status, responseText) {
  console.log('Status: ' + status);

  if (status >= 200 && status < 300) {
    console.log('Success!');
    const data = JSON.parse(responseText);
    console.log('Data: ' + JSON.stringify(data));
  } else if (status === 404) {
    console.log('Resource not found');
  } else if (status === 500) {
    console.log('Server error');
  } else {
    console.log('Unexpected status: ' + status);
  }
}

handleResponse(200, '{"message": "ok"}');
handleResponse(404, '{}');
handleResponse(500, '{}');

readyState and onreadystatechange

The readyState property tracks the state of the XMLHttpRequest. The onreadystatechange event fires every time readyState changes. The request is complete when readyState is 4.

readyStateValueDescription
UNSENT0open() not yet called
OPENED1open() has been called
HEADERS_RECEIVED2send() called, headers received
LOADING3Downloading response body
DONE4Operation complete
readyState Changes
// Track readyState changes
// xhr.onreadystatechange = function() {
//   console.log('readyState: ' + xhr.readyState);
//   if (xhr.readyState === 4 && xhr.status === 200) {
//     console.log('Response: ' + xhr.responseText);
//   }
// };

// Simulating readyState progression
const states = [
  { state: 0, name: 'UNSENT' },
  { state: 1, name: 'OPENED' },
  { state: 2, name: 'HEADERS_RECEIVED' },
  { state: 3, name: 'LOADING' },
  { state: 4, name: 'DONE' }
];

states.forEach(function(s) {
  console.log('readyState ' + s.state + ': ' + s.name);
});

console.log('\nCheck readyState === 4 && status === 200 for success');

Parsing JSON Response

Most modern APIs return JSON data. The responseText is a string that must be parsed with JSON.parse() to become a usable JavaScript object.

Full AJAX Response Handling
// Complete AJAX pattern with JSON parsing
function makeRequest(url) {
  // const xhr = new XMLHttpRequest();
  // xhr.open('GET', url, true);

  // xhr.onreadystatechange = function() {
  //   if (xhr.readyState === 4) {
  //     if (xhr.status === 200) {
  //       const data = JSON.parse(xhr.responseText);
  //       displayData(data);
  //     } else {
  //       handleError(xhr.status);
  //     }
  //   }
  // };
  // xhr.send();

  console.log('Request to: ' + url);
}

// Simulating JSON response parsing
const jsonResponse = '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]';
const users = JSON.parse(jsonResponse);

users.forEach(function(user) {
  console.log('User ' + user.id + ': ' + user.name);
});

makeRequest('/api/users');

Error Handling

Proper error handling is essential for AJAX requests. Handle network errors, HTTP errors, and JSON parsing errors separately for robust applications.

Comprehensive Error Handling
function handleAjaxResponse(readyState, status, responseText) {
  // Check if request is complete
  if (readyState !== 4) {
    console.log('Request still in progress...');
    return;
  }

  // Check HTTP status
  if (status === 0) {
    console.log('Network error - could not connect');
    return;
  }

  if (status !== 200) {
    console.log('HTTP error: ' + status);
    return;
  }

  // Try to parse JSON
  try {
    const data = JSON.parse(responseText);
    console.log('Success: ' + JSON.stringify(data));
  } catch (e) {
    console.log('JSON parse error: ' + e.message);
  }
}

handleAjaxResponse(4, 200, '{"ok": true}');
handleAjaxResponse(4, 404, 'Not Found');
handleAjaxResponse(4, 0, '');
handleAjaxResponse(4, 200, 'not json');
📝 Note: Modern JavaScript development favors the Fetch API over XMLHttpRequest for new projects. However, understanding XHR is valuable because many legacy codebases use it, and some features like upload progress tracking are easier with XHR. The onload event can be used instead of onreadystatechange for cleaner code when you only need the final response.
Exercise:
What value of readyState indicates that the AJAX request is complete?
Try it YourselfCtrl+Enter to run
Click Run to see the output here.