asynchronous programming
javascript
promises
async/await
event loop

Asynchronous programming in javascript NOT AJAX

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Asynchronous programming in JavaScript is much broader than AJAX. It is the general technique that lets JavaScript start work now, continue doing other things, and handle the result later without blocking the main thread.

Why JavaScript needs asynchronous patterns

JavaScript typically runs on a single main thread for user code. If every slow operation blocked that thread, the page or process would feel frozen while waiting for timers, disk access, network responses, or other external events.

That is why JavaScript relies on an event loop. The event loop coordinates:

  • the call stack
  • task queues
  • APIs that finish later and schedule callbacks

A simple timer example already shows asynchronous behavior without any AJAX:

javascript
1console.log("start");
2
3setTimeout(() => {
4  console.log("timer finished");
5}, 1000);
6
7console.log("end");

The output order is:

text
start
end
timer finished

The timer is asynchronous because JavaScript keeps running other code while the timeout counts down.

Callbacks are the original async style

The oldest common pattern is a callback: pass a function now and let some later event call it.

javascript
1const fs = require("fs");
2
3fs.readFile("notes.txt", "utf8", (err, data) => {
4  if (err) {
5    console.error(err);
6    return;
7  }
8
9  console.log(data);
10});
11
12console.log("File read started");

This example is asynchronous even though it has nothing to do with a browser request. The file system operation starts, JavaScript continues, and the callback runs later.

Promises make async flow easier to compose

Callbacks work, but they become hard to read when many async steps depend on one another. Promises give you a value that will settle in the future.

javascript
1function wait(ms) {
2  return new Promise((resolve) => {
3    setTimeout(resolve, ms);
4  });
5}
6
7wait(500)
8  .then(() => {
9    console.log("half a second passed");
10    return wait(500);
11  })
12  .then(() => {
13    console.log("one second total");
14  });

A promise-based API lets you chain dependent steps and centralize error handling more cleanly than nested callbacks.

async and await are syntax on top of promises

async and await do not replace asynchronous programming; they make promise-based async code easier to read.

javascript
1function wait(ms) {
2  return new Promise((resolve) => {
3    setTimeout(resolve, ms);
4  });
5}
6
7async function run() {
8  console.log("before wait");
9  await wait(1000);
10  console.log("after wait");
11}
12
13run();

The function pauses logically at await, but the thread is not blocked. The rest of the program can still process other tasks while the promise is pending.

Async is not only about networking

AJAX is just one example of asynchronous work. Other common async cases include:

  • timers
  • user events
  • file I/O in Node.js
  • database calls
  • animation frames
  • worker messages

For example, a button click handler is also event-driven and asynchronous relative to the rest of the program:

javascript
document.getElementById("saveButton").addEventListener("click", () => {
  console.log("User clicked save");
});

The handler is registered now and invoked later when the event occurs.

Concurrency without parallel thinking mistakes

JavaScript async code can make many operations overlap in time even when user code stays single-threaded. For example:

javascript
1async function run() {
2  const first = wait(1000);
3  const second = wait(1000);
4
5  await Promise.all([first, second]);
6  console.log("Both finished");
7}

This is concurrency: both waits are in progress together. It is different from writing:

javascript
await wait(1000);
await wait(1000);

which runs them sequentially.

Common Pitfalls

The biggest mistake is thinking asynchronous programming means only HTTP requests. Timers, events, file access, database calls, and many browser or Node.js APIs use the same async model.

Another issue is assuming await blocks the thread the way sleep would in some other languages. It does not. It pauses the async function while allowing the event loop to continue handling other tasks.

Developers also mix callback, promise, and async styles carelessly in one code path, which makes control flow hard to reason about. Pick a clear style at each API boundary.

Finally, asynchronous code does not automatically make CPU-heavy work cheap. A long synchronous loop still blocks the event loop, even inside an async function.

Summary

  • JavaScript asynchronous programming is broader than AJAX.
  • The event loop lets slow operations complete later without blocking ordinary execution.
  • Callbacks, promises, and async and await are all ways to structure async behavior.
  • Timers, file I/O, events, and background APIs are common async use cases.
  • 'await pauses a function logically, but it does not stop the event loop itself.'

Course illustration
Course illustration

All Rights Reserved.