Understanding Asynchronous Requests
Asynchronous requests allow your web application to communicate with the server without blocking the user interface. This enables a smooth, responsive user experience where users can continue interacting with the page while data loads in the background.
The key difference between synchronous and asynchronous requests is that async requests don’t block code execution. The JavaScript continues running while waiting for the server response.
The Asynchronous Flow
Initiate the request
JavaScript sends an HTTP request to the server and continues executing.
User continues interacting
The page remains responsive while waiting for the server response.
Receive the response
When the server responds, a callback function processes the data.
Update the UI
The DOM is updated with the new data without reloading the page.
Callback Pattern
The traditional approach to handling asynchronous responses uses callback functions:
let peticion;
const iniciar = () => {
peticion = new XMLHttpRequest();
peticion.open('GET', "fecha.php");
peticion.send();
// The callback function is registered
peticion.addEventListener("load", cargada);
// Code continues executing here immediately
console.log("Request sent, but response not received yet!");
}
// This callback executes when the response arrives
const cargada = () => {
console.log("Now we have the response!");
document.getElementById("resultados").innerText = peticion.responseText;
}
window.addEventListener("load", iniciar, false);
Plain Text
The simplest format, suitable for basic messages:
const cargada = () => {
document.getElementById("resultados").innerText = peticion.responseText;
}
Receive formatted HTML from the server and inject it into the DOM:
const cargada = () => {
document.getElementById("resultados").innerHTML = peticion.responseText;
}
<?php
echo "<h2>Hello from the server!</h2>";
echo "<p>The current time is " . date("H:i:s") . "</p>";
?>
Parse structured XML data from the server:
let peticion;
const iniciar = () => {
peticion = new XMLHttpRequest();
peticion.open('GET', "datosxml.php");
peticion.send();
peticion.addEventListener("load", cargada);
}
const cargada = () => {
let resultados = '';
let cds = peticion.responseXML.documentElement.getElementsByTagName("CD");
resultados += '<ul>';
for (let i = 0; i < cds.length; i++) {
resultados += `<li><b>CD nº ${i + 1}</b><ul>`;
resultados += `<li><b>TÃtulo:</b> ${cds[i].getElementsByTagName('TITLE')[0].innerHTML}</li>`;
resultados += `<li><b>Artista:</b> ${cds[i].getElementsByTagName('ARTIST')[0].innerHTML}</li>`;
resultados += `<li><b>PaÃs:</b> ${cds[i].getElementsByTagName('COUNTRY')[0].innerHTML}</li>`;
resultados += `<li><b>CompañÃa:</b> ${cds[i].getElementsByTagName('COMPANY')[0].innerHTML}</li>`;
resultados += `<li><b>Precio:</b> ${cds[i].getElementsByTagName('PRICE')[0].innerHTML}</li>`;
resultados += `<li><b>Año:</b> ${cds[i].getElementsByTagName('YEAR')[0].innerHTML}</li>`;
resultados += `</li></ul>`;
}
resultados += '</ul>';
document.getElementById("resultados").innerHTML = resultados;
}
window.addEventListener("load", iniciar, false);
JSON is the most popular format for modern web applications:
let peticion;
const iniciar = () => {
peticion = new XMLHttpRequest();
peticion.open('GET', "datosjson.php");
peticion.send();
peticion.addEventListener("load", cargada);
}
const cargada = () => {
let resultados = '';
// Parse JSON response
let cds = JSON.parse(peticion.responseText);
resultados += '<ul>';
for (let i = 0; i < cds.length; i++) {
resultados += `<li><b>CD nº ${i + 1}</b><ul>`;
resultados += `<li><b>TÃtulo:</b> ${cds[i].title}</li>`;
resultados += `<li><b>Artista:</b> ${cds[i].artist}</li>`;
resultados += `<li><b>PaÃs:</b> ${cds[i].country}</li>`;
resultados += `<li><b>CompañÃa:</b> ${cds[i].company}</li>`;
resultados += `<li><b>Precio:</b> ${cds[i].price}</li>`;
resultados += `<li><b>Año:</b> ${cds[i].year}</li>`;
resultados += `</li></ul>`;
}
resultados += '</ul>';
document.getElementById("resultados").innerHTML = resultados;
}
window.addEventListener("load", iniciar, false);
Always validate and sanitize JSON data on both the client and server sides to prevent security vulnerabilities.
jQuery AJAX Shortcuts
While XMLHttpRequest provides full control, jQuery offers convenient shortcuts:
$.ajax() Method
$(document).ready(() => {
$.ajax({
url: 'fecha.php',
type: 'GET',
async: true,
success: (respuesta) => {
$("#resultados").text(respuesta);
$("#estado").toggleClass('cargada');
$("#estado").text("Cargada.");
},
error: (xhr, status, error) => {
console.error("Error: " + error);
}
});
});
$.post() Shorthand
$(document).ready(() => {
$.post(
'procesar.php',
'nombre=Bob&apellidos=Esponja',
(respuesta) => {
$("#resultados").html(respuesta);
}
);
});
$.get() Shorthand
$.get('datos.php', { id: 123 }, (data) => {
console.log(data);
});
$.getJSON() for JSON Data
$.getJSON('datosjson.php', (cds) => {
cds.forEach((cd, index) => {
console.log(`${index + 1}. ${cd.title} by ${cd.artist}`);
});
});
Error Handling
Always implement proper error handling for robust applications:
let peticion;
const iniciar = () => {
peticion = new XMLHttpRequest();
peticion.open('GET', "datos.php");
// Success handler
peticion.addEventListener("load", () => {
if (peticion.status === 200) {
document.getElementById("resultados").innerText = peticion.responseText;
} else {
mostrarError(`Server error: ${peticion.status}`);
}
});
// Error handler
peticion.addEventListener("error", () => {
mostrarError("Network error occurred");
});
// Timeout handler
peticion.addEventListener("timeout", () => {
mostrarError("Request timed out");
});
peticion.timeout = 5000; // 5 second timeout
peticion.send();
}
const mostrarError = (mensaje) => {
document.getElementById("estado").innerText = mensaje;
document.getElementById("estado").classList.add('error');
}
Loading States
Provide visual feedback during asynchronous operations:
const iniciar = () => {
// Show loading state
document.getElementById("estado").classList = ['cargando'];
document.getElementById("estado").innerText = "Cargando...";
document.getElementById("resultados").innerHTML = "<p>Loading data...</p>";
peticion = new XMLHttpRequest();
peticion.open('GET', "datos.php");
peticion.send();
peticion.addEventListener("load", cargada);
}
const cargada = () => {
// Update to loaded state
document.getElementById("resultados").innerText = peticion.responseText;
document.getElementById("estado").classList = ['cargada'];
document.getElementById("estado").innerText = "Cargada.";
}
.cargando {
background: #ff9800;
color: white;
padding: 10px;
border-radius: 4px;
}
.cargada {
background: #4caf50;
color: white;
padding: 10px;
border-radius: 4px;
}
.error {
background: #f44336;
color: white;
padding: 10px;
border-radius: 4px;
}
Best Practices
Set appropriate timeouts
Always configure timeout values to prevent requests from hanging indefinitely.
Handle all response codes
Check HTTP status codes and handle both success and error cases.
Provide user feedback
Show loading indicators and error messages to keep users informed.
Use proper content types
Set correct Content-Type headers on the server for different data formats.
Sanitize data
Always validate and sanitize data on both client and server sides.
Common Pitfalls
Cross-Origin Requests: AJAX requests are subject to Same-Origin Policy. Use CORS headers on the server to allow cross-origin requests when needed.
Caching Issues: Browsers may cache GET requests. Add cache-busting parameters or use appropriate Cache-Control headers if you need fresh data every time.
Next Steps
Explore more advanced AJAX patterns: