async / await
| Since: | ES2017(ECMAScript 2017) |
|---|
A syntax for writing asynchronous code in an intuitive, synchronous style. Use async to declare an asynchronous function and await to wait for a Promise to resolve.
Syntax
// Declares an async function. The return value is automatically wrapped in a Promise.
async function functionName() {
// Waits for the Promise to resolve.
var result = await Promise;
}
// Using a function expression
var functionName = async function() {
var result = await Promise;
};
Keywords
| Keyword | Description |
|---|---|
| async | Placed before a function to make it an asynchronous function. An async function always returns a Promise. |
| await | Waits for a Promise to resolve and extracts the resulting value. Can only be used inside an async function. |
Sample Code
The following samples use a helper function for testing. Please read the promise page first to understand the basics of Promises.
// A helper async function for testing
function wait(ms) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve("Waited " + ms + "ms");
}, ms);
});
}
// Basic usage of async/await
async function main() {
console.log("Start");
var result = await wait(2000); // Waits for 2 seconds.
console.log(result); // Logs "Waited 2000ms".
console.log("Done");
}
main();
// Comparison with the then() chain approach
// then() version
wait(1000).then(function(msg1) {
console.log(msg1);
return wait(1000);
}).then(function(msg2) {
console.log(msg2);
});
// async/await version
async function sequential() {
var msg1 = await wait(1000);
console.log(msg1); // Logs "Waited 1000ms".
var msg2 = await wait(1000);
console.log(msg2); // Logs "Waited 1000ms" one more second later.
}
sequential();
// Handling errors with try...catch.
async function fetchUserData() {
try {
var response = await fetch("https://wp-p.info/sandbox/api.php");
var data = await response.json();
console.log(data.name);
} catch (error) {
console.log("Failed to fetch data: " + error.message);
} finally {
console.log("Network request finished");
}
}
fetchUserData();
// Running multiple async operations in parallel
async function loadAll() {
// Combine Promise.all() with await to wait for all operations to finish.
var results = await Promise.all([
fetch("https://wp-p.info/sandbox/api.php"),
fetch("https://wp-p.info/sandbox/api.php")
]);
console.log("All data loaded");
}
loadAll();
※ Run the fetch() sample in the browser's developer tools (Console tab).
Start Waited 2000ms Done Waited 1000ms Waited 1000ms Waited 1000ms
Return Value of async Functions
An async function always returns a Promise. A value returned with return is automatically wrapped in Promise.resolve(), so the caller can receive it with await or then().
// The return value of an async function is wrapped in Promise.resolve().
async function getGreeting() {
return "Hello, Iori!";
}
// Since the return value is a Promise, use await to extract it.
async function show() {
var message = await getGreeting();
console.log(message); // Prints "Hello, Iori!".
}
show();
// You can also use then().
getGreeting().then(function(msg) {
console.log(msg); // Prints "Hello, Iori!".
});
// If there is no explicit return, a Promise of undefined is returned.
async function noReturn() {
console.log("Processing");
}
noReturn().then(function(result) {
console.log(result); // Prints "undefined".
});
Using await in Loops
Using await inside a for loop executes asynchronous operations one at a time in order. However, this is slow since operations run in series. Use Promise.all() for parallel execution.
// Serial execution: processes one at a time (takes 3 seconds total).
async function serial() {
var urls = ["/api/users", "/api/posts", "/api/comments"];
var i;
for (i = 0; i < urls.length; i++) {
var response = await fetch(urls[i]);
console.log("Fetched " + urls[i]);
}
}
// Parallel execution: starts all at once (takes as long as the slowest one).
async function parallel() {
var urls = ["/api/users", "/api/posts", "/api/comments"];
var promises = urls.map(function(url) {
return fetch(url);
});
var responses = await Promise.all(promises);
console.log("Fetched " + responses.length + " resources");
}
Using await inside forEach() does not wait (because forEach is not an async function). Always use a regular for loop when you need to await sequentially.
NG: await inside forEach does not wait.
async function wrong() {
var ids = [1, 2, 3];
ids.forEach(async function(id) {
var data = await fetch("/api/users/" + id);
console.log(id); // Order is not guaranteed
});
console.log("Done"); // Runs without waiting for forEach's awaits
}
OK: A for loop waits in order.
async function correct() {
var ids = [1, 2, 3];
var i;
for (i = 0; i < ids.length; i++) {
var data = await fetch("/api/users/" + ids[i]);
console.log(ids[i]); // Prints 1, 2, 3 in order
}
console.log("Done"); // Runs after all iterations complete
}
Common mistake 1: forgetting await
Forgetting await leaves a Promise object in the variable instead of the resolved value.
async function mistake1() {
var data = fetch("/api/users"); // No await — stores a Promise object
console.log(data); // Prints "Promise { <pending> }"
}
Correct: Add await to get the response.
async function correct1() {
var response = await fetch("/api/users");
var data = await response.json();
console.log(data); // Prints the JSON response data
}
Common mistake 2: forgetting async
Using await without async causes a SyntaxError.
// Using await in a non-async function causes a SyntaxError
function mistake2() {
// var result = await fetch("/api"); // SyntaxError
}
// Mistake 3: Not catching errors leads to Unhandled Promise Rejection
async function mistake3() {
var response = await fetch("https://invalid-url.example.com");
// A network error occurs, but since it is not caught,
// an Unhandled Promise Rejection warning appears in the console
}
// mistake3(); // Always wrap in try...catch or append .catch()
Practical Pattern: Loading Indicator
In web applications, a common pattern is to show a loading indicator while fetching data and hide it when done.
<button id="loadBtn">Fetch Data</button> <p id="loading" style="display: none;">Loading...</p> <div id="result"></div>
var loadBtn = document.getElementById("loadBtn");
var loading = document.getElementById("loading");
var result = document.getElementById("result");
if (loadBtn && loading && result) {
loadBtn.addEventListener("click", async function() {
// Show the loading indicator.
loading.style.display = "block";
loadBtn.disabled = true;
try {
var response = await fetch("https://wp-p.info/sandbox/api.php");
var data = await response.json();
result.textContent = "Fetched: " + JSON.stringify(data);
} catch (error) {
result.textContent = "Error: " + error.message;
} finally {
// Hide the loading indicator (runs on both success and failure).
loading.style.display = "none";
loadBtn.disabled = false;
}
});
}
Using a finally block ensures the loading indicator is always hidden, regardless of success or failure. Disabling the button during the request also prevents double submissions.
Notes on await
await can only be used inside an async function. Using it in a regular function or at the global scope causes an error.
// Incorrect — causes an error
function normal() {
var result = await wait(1000); // SyntaxError: await cannot be used outside an async function.
}
// Correct — used inside an async function
async function correct() {
var result = await wait(1000); // Works as expected.
console.log(result);
}
correct();
Also, writing multiple await calls sequentially runs them one after another. For independent operations, use Promise.all() to run them in parallel for better performance.
// Sequential execution: takes 3 seconds total.
async function slow() {
var a = await wait(1000); // Waits 1 second.
var b = await wait(2000); // Waits another 2 seconds.
console.log(a, b);
}
// Parallel execution: completes in 2 seconds (the slowest task).
async function fast() {
var results = await Promise.all([wait(1000), wait(2000)]);
console.log(results[0], results[1]);
}
Overview
async / await is a syntax introduced in ES2017 for working with Promises more concisely. With Promise chains using then(), the more complex the logic, the harder the code becomes to read. With async / await, you can write asynchronous code that looks just like ordinary synchronous code.
An async function always returns a Promise. When you return a value from inside the function, it is automatically wrapped in Promise.resolve(). If an error is thrown, it is wrapped in Promise.reject(), and the caller can handle it with catch() or try...catch.
async / await is commonly used for asynchronous code. It is an intuitive syntax for tasks that require waiting — such as server communication, database queries, and file I/O.
Browser Compatibility
51 or earlier ×
Android Browser
60+ ○
54 or earlier ×
Chrome Android
60+ ○
54 or earlier ×
Firefox Android
79+ ○
51 or earlier ×If you find any errors or copyright issues, please contact us.