Asynchronous JavaScript

Asynchronous JavaScript allows a program to start an operation and continue executing other code while waiting for that operation to finish. It is especially useful for tasks such as fetching data from an API, reading files, handling timers, and communicating with a server.

JavaScript code can execute synchronously or asynchronously. Understanding the difference helps you write applications that remain responsive while waiting for operations to complete.

In this tutorial, you will learn what synchronous and asynchronous JavaScript mean, how blocking and non-blocking operations work, and why asynchronous programming is important in modern web development.

What Is Synchronous JavaScript?

Synchronous JavaScript executes statements one after another, in order. Each statement generally needs to finish before the next statement begins executing.

This means that if one operation takes a long time to complete, later statements must wait.

Example of Synchronous JavaScript

console.log("First");

console.log("Second");

console.log("Third");

Output:

First
Second
Third

JavaScript executes the first statement, then the second, and finally the third.

Each console.log() call completes before execution moves to the next statement.

Example with a Function

function greet() {
  console.log("Hello!");
}

console.log("Start");

greet();

console.log("End");

Output:

Start
Hello!
End

When JavaScript calls greet(), it executes the function before continuing to the next statement.

This is an example of synchronous execution.

How Synchronous Execution Works

Synchronous execution follows a straightforward sequence:

  • JavaScript starts executing the code.
  • The current statement runs to completion.
  • The next statement executes.
  • This process continues until the program finishes or encounters a control-flow change.

Synchronous code is easy to understand and is suitable for many everyday tasks, such as calculations, variable assignments, and simple function calls.

However, a long-running synchronous operation can prevent other JavaScript tasks from running until that operation finishes.

What Is Asynchronous JavaScript?

Asynchronous JavaScript allows certain operations to complete later without requiring the surrounding code to wait synchronously for the entire operation.

This is useful when a program needs to wait for a timer, a network response, or another operation that completes outside the immediate execution of the current code.

JavaScript commonly handles asynchronous operations using callbacks, Promises, and async/await.

Example of Asynchronous JavaScript

console.log("Start");

setTimeout(function () {
  console.log("Inside timeout");
}, 2000);

console.log("End");

Output:

Start
End
Inside timeout

The setTimeout() function schedules a callback to run after approximately two seconds. JavaScript does not wait for those two seconds before executing console.log("End").

The callback runs later when its timer has expired and the JavaScript runtime can execute it.

The delay is not a guarantee that the callback will run at exactly two seconds. Other work may delay its execution.

How Asynchronous Execution Works

In a typical browser environment, asynchronous execution involves several parts:

  • JavaScript executes the current code.
  • The browser or runtime manages supported asynchronous operations, such as timers and network requests.
  • When an operation is ready to continue, its callback or Promise continuation is scheduled.
  • The event loop helps determine when queued work can run.

JavaScript in a browser generally executes JavaScript callbacks on a single main thread at a time. Asynchronous operations allow it to avoid waiting synchronously for many tasks, but they do not automatically make CPU-intensive JavaScript calculations run in parallel.

Example of Waiting for a Timer

console.log("Preparing");

setTimeout(function () {
  console.log("Timer completed");
}, 1000);

console.log("Continuing");

Output:

Preparing
Continuing
Timer completed

The program continues executing after scheduling the timer. The callback runs later, once the timer has expired and the runtime can execute it.

This pattern is useful for delayed actions, animations, and other tasks that do not need to block the current execution.

Blocking vs Non-Blocking JavaScript

Blocking and non-blocking describe whether an operation prevents other work from progressing while it is being performed.

A blocking operation makes the current execution wait until the operation finishes. A non-blocking operation allows execution to continue while the operation is handled or awaited through an asynchronous mechanism.

What Is Blocking JavaScript?

Blocking JavaScript occurs when an operation occupies the JavaScript execution thread for long enough that other work cannot run on that thread.

For example, a large synchronous calculation or an infinite loop can prevent the browser from responding to clicks, updating the page, or running other JavaScript callbacks.

Example of Blocking Code

console.log("Start");

const start = Date.now();

while (Date.now() - start < 3000) {
  // Busy-wait for approximately three seconds
}

console.log("Finished waiting");

Output after the delay:

Start
Finished waiting

The while loop repeatedly checks the time for approximately three seconds. During that time, the JavaScript thread is busy executing the loop.

In a browser, this kind of blocking work can make the page temporarily unresponsive.

This example is for demonstrating blocking behavior. Avoid using busy-wait loops in real applications.

What Is Non-Blocking JavaScript?

Non-blocking JavaScript allows execution to continue without waiting synchronously for an operation to finish.

For example, a timer can be scheduled and JavaScript can continue running other statements while the runtime waits for the timer.

Example of Non-Blocking Code

console.log("Start");

setTimeout(function () {
  console.log("Operation completed");
}, 3000);

console.log("Other work continues");

Output:

Start
Other work continues
Operation completed

The timer does not occupy the JavaScript thread for the entire three-second delay. JavaScript continues executing the remaining statement, and the callback runs later.

This makes non-blocking techniques useful for operations such as waiting for network responses or scheduling delayed actions.

Blocking vs Non-Blocking: Comparison

FeatureBlockingNon-Blocking
ExecutionWaits synchronously for the operation to finishAllows execution to continue while an operation is pending
ResponsivenessLong operations can make a page unresponsiveHelps keep the page responsive when used appropriately
Common examplesLong synchronous loops and synchronous I/OTimers, asynchronous network requests, and Promise-based APIs
Effect on later codeLater statements cannot execute until the blocking operation finishesLater statements can execute before the asynchronous operation completes
Best suited forShort, straightforward synchronous operationsOperations involving waiting, such as network requests

Non-blocking does not mean that an operation finishes instantly. It means that the program does not have to wait synchronously for that operation to complete.

Why Is Asynchronous JavaScript Important?

Modern websites frequently perform operations that take time, such as retrieving data from a server, loading content, or sending information to an API.

If every operation blocked JavaScript until completion, a page could become slow or unresponsive while waiting.

Asynchronous JavaScript helps applications:

  • Fetch data without synchronously waiting for a network response.
  • Keep interfaces responsive while waiting for operations.
  • Schedule tasks to run later.
  • Handle multiple pending operations without requiring each one to finish before the next begins.
  • Update webpage content when data becomes available.

For example, a weather application can request weather information from an API while the rest of the interface remains available to the user.

Asynchronous programming does not eliminate all performance problems. Long-running synchronous JavaScript can still block the main thread, and excessive concurrent requests can still affect application performance.

Common Ways to Handle Asynchronous JavaScript

JavaScript provides several patterns for working with asynchronous operations.

Callbacks

A callback is a function passed to another function so it can be called later.

setTimeout(function () {
  console.log("This callback runs later");
}, 1000);

The callback passed to setTimeout() runs after the timer expires and the runtime can execute it.

Callbacks are useful for many event handlers and asynchronous APIs.

Promises

A Promise represents the eventual completion or failure of an asynchronous operation.

const task = new Promise(function (resolve) {
  setTimeout(function () {
    resolve("Task completed");
  }, 1000);
});

task.then(function (message) {
  console.log(message);
});

Output after the delay:

Task completed

The Promise is fulfilled when resolve() is called. The .then() callback runs when the Promise continuation is scheduled.

Async and Await

The async and await keywords provide a convenient way to write asynchronous code that looks similar to synchronous code.

function wait() {
  return new Promise(function (resolve) {
    setTimeout(resolve, 1000);
  });
}

async function runTask() {
  console.log("Start");

  await wait();

  console.log("Task completed");
}

runTask();

Output:

Start
Task completed

When execution reaches await wait(), the runTask() function pauses its own progress until the Promise settles. JavaScript can continue running other work in the meantime.

An await expression does not block the entire JavaScript thread while waiting for a Promise.

You will learn these techniques in more detail in the upcoming tutorials on JavaScript Callback Functions and JavaScript Async/Await.

Frequently Asked Questions

What is synchronous JavaScript?

Synchronous JavaScript executes statements in sequence. The current statement generally completes before the next statement begins.

What is asynchronous JavaScript?

Asynchronous JavaScript allows an operation to remain pending while the program continues executing other work. Callbacks, Promises, and async/await are common ways to work with asynchronous operations.

What is the difference between synchronous and asynchronous JavaScript?

Synchronous code waits for each operation to complete before moving forward. Asynchronous code allows certain operations to complete later while other work continues.

What is blocking JavaScript?

Blocking JavaScript occupies the execution thread and prevents other work on that thread from running until the blocking operation finishes.

What is non-blocking JavaScript?

Non-blocking JavaScript allows the program to continue executing while an operation is pending, rather than waiting synchronously for it to finish.

Does asynchronous JavaScript mean that code runs in parallel?

No. Asynchronous execution and parallel execution are different concepts. JavaScript can schedule work to continue later without running multiple JavaScript callbacks simultaneously on the same thread. Parallel JavaScript execution is possible in certain environments, such as through Web Workers in browsers.

Is setTimeout() an example of asynchronous JavaScript?

Yes. setTimeout() schedules a callback to run after a specified delay. It does not pause the entire JavaScript thread for that duration.

Why is asynchronous JavaScript useful in web development?

It helps websites handle network requests, timers, and other waiting operations without requiring the current JavaScript execution to stop until those operations finish.

Conclusion

Asynchronous JavaScript is an important part of modern web development. Synchronous code executes in sequence, while asynchronous techniques allow operations to complete later without requiring the entire program to wait.

Understanding blocking and non-blocking behavior helps you build responsive applications and avoid performance problems. These fundamentals prepare you to learn callbacks, Promises, the event loop, and async/await in greater detail.