Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

How AJAX Works: Tutorial, Examples, FAQs & Interview Tips

Step-by-Step AJAX Flow

Understanding the AJAX lifecycle helps you write better asynchronous code and debug issues more effectively. Here is the complete flow from user interaction to DOM update:

  1. User Event - The user triggers an action: a button click, a keypress in a search box, a form submission, or a scroll event.
  2. JavaScript Creates a Request - An event listener fires and JavaScript creates either an XMLHttpRequest object or calls the fetch() function.
  3. Request Sent to Server - The browser sends an HTTP request (GET, POST, etc.) to the server URL in the background. The page remains fully interactive.
  4. Server Processes the Request - The server-side code (PHP, Node.js, Python, etc.) receives the request, queries a database or performs logic, and prepares a response.
  5. Server Returns a Response - The server sends back data - typically JSON, but sometimes XML, HTML fragments, or plain text.
  6. JavaScript Receives the Response - A callback function, Promise .then(), or await expression receives the response data.
  7. DOM is Updated - JavaScript parses the response and updates only the relevant part of the page. No full reload occurs.
Complete AJAX Flow Example
// Step 1: User event - button click
document.getElementById('load-btn').addEventListener('click', function () {

  // Step 2: Show a loading indicator
  document.getElementById('result').textContent = 'Loading...';

  // Step 3: Create and send the request
  fetch('/api/data')
    // Step 6: Receive and parse the response
    .then(response => {
      if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
      return response.json();
    })
    // Step 7: Update the DOM
    .then(data => {
      document.getElementById('result').innerHTML =
        `<p>Received: ${data.message}</p>`;
    })
    .catch(error => {
      document.getElementById('result').textContent = `Error: ${error.message}`;
    });
});

Synchronous vs Asynchronous

Synchronous code executes line by line. Each line must finish before the next one starts. If a network request takes 3 seconds, the entire browser tab freezes for 3 seconds - the user cannot click, scroll, or type.

Asynchronous code allows the browser to continue executing other code while waiting for a slow operation (like a network request) to complete. When the operation finishes, a callback or Promise resolves and handles the result.

Synchronous vs Asynchronous Comparison
// ---- SYNCHRONOUS (blocks the thread) ----
// XMLHttpRequest with async=false - NEVER do this in production
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data', false); // false = synchronous
xhr.send();
// Browser is FROZEN here until the request completes
console.log('This runs only after the request finishes');

// ---- ASYNCHRONOUS (non-blocking) ----
// Using fetch - the browser stays responsive
console.log('1. Before fetch');

fetch('/api/data')
  .then(res => res.json())
  .then(data => {
    console.log('3. Data received:', data); // runs later
  });

console.log('2. After fetch call'); // runs immediately, before data arrives
// Output order: 1 -> 2 -> 3

The JavaScript Event Loop

JavaScript is single-threaded - it can only do one thing at a time. The event loop is the mechanism that makes asynchronous code possible without multiple threads.

  • Call Stack - where synchronous code executes, one frame at a time.
  • Web APIs - browser-provided APIs (like fetch, setTimeout) that handle async operations outside the call stack.
  • Callback Queue / Task Queue - completed async callbacks wait here to be pushed onto the call stack.
  • Microtask Queue - Promise callbacks (.then(), await) go here and are processed before the regular task queue.
  • Event Loop - continuously checks if the call stack is empty, then pushes the next task from the queue.
Event Loop Execution Order
console.log('A'); // synchronous - runs first

setTimeout(() => {
  console.log('B'); // macro-task - runs last
}, 0);

Promise.resolve().then(() => {
  console.log('C'); // micro-task - runs before setTimeout
});

console.log('D'); // synchronous - runs second

// Output: A -> D -> C -> B
// Explanation:
// 1. Synchronous code runs: A, D
// 2. Microtask queue drains: C (Promise callbacks)
// 3. Macro-task queue: B (setTimeout)

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.