await in arrow functions
Yes, you can use await inside an arrow function, but only when that arrow is declared with the async keyword. The shape of the function is irrelevant here: it is async that grants permission to use await, not the arrow or the function keyword.
Theory
TL;DR
awaitis allowed only inside anasyncfunction or at the top level of an ES module.- An arrow function becomes asynchronous just as easily:
async () => { ... }. - Without
asyncyou get aSyntaxError, and the code does not run at all, because the error happens at parse time. - Any
asyncfunction, arrow ones included, always returns a promise. - An
asyncarrow can be passed as a callback, for example into.then(), andawaitinside it is perfectly legal. - Outside a function,
awaitworks only as top-level await in ESM.
Quick example
const fetchData = async () => {
const data = await Promise.resolve('Done');
console.log(data);
};
fetchData();Result:
Doneasync in front of an arrow function turns it into an asynchronous function that always returns a promise.
Where await is allowed at all
await is an operator you may use in exactly two places:
- inside a function declared with
async; - at the top level of a module (top-level await).
Using await outside async is a syntax error:
// Error
const result = await Promise.resolve(42);
// SyntaxError: await is only valid in async functionsThe same goes for a plain arrow without async:
const foo = () => {
const data = await Promise.resolve('value');
console.log(data);
};
// SyntaxError: await is only valid in async functionsNote that this is not a runtime error. JS will not even start executing the code, because await is not permitted in a normal function, so the script fails while it is still being parsed.
What an async arrow returns
An async arrow always returns a promise, even when it contains no await at all:
const sum = async (a, b) => a + b;
console.log(sum(1, 2)); // Promise { 3 }That is the same as writing:
function sum(a, b) {
return Promise.resolve(a + b);
}So the result of such a function has to be either awaited or handled through .then().
Different ways to write it
An arrow with await in its plain form:
const loadUser = async () => {
const res = await fetch('/api/user');
return res.json();
};With parameters:
const getUser = async (id) => {
const res = await fetch(`/api/user/${id}`);
return res.json();
};A multi-line form:
const processData = async () => {
const data = await fetch('/api/data');
const json = await data.json();
console.log(json);
};Inside a promise chain:
Promise.resolve('A')
.then(async (x) => {
const y = await Promise.resolve('B');
return x + y;
})
.then(console.log); // "AB"Here then() takes an async arrow function and await inside it is entirely legal: then simply waits for the promise that this function returns.
Top-level await
Modern JS modules (ESM) let you use await outside functions, as long as the code really runs as a module and not as a plain <script> without type="module":
// main.js
const data = await fetch('/api/data').then(r => r.json());
console.log(data);This is top-level await. It works only in ESM (in the browser with <script type="module">, or in Node.js with "type": "module" in package.json). In a CommonJS module such code will not run.
A simple analogy:
asyncin front of an arrow function is a pass that gives you the right to useawaitinside. Without it the engine simply does not know where to deliver the awaited result.
Summary table
| Question | Answer |
|---|---|
Can await be used in an arrow function? | Yes, if it is declared as async |
What happens without async? | SyntaxError: await is only valid in async functions |
What does an async arrow return? | Always a Promise |
Can await appear in .then() or in callbacks? | Yes, if the callback itself is declared async |
Can await be used outside a function? | Only as top-level await in modules |
Common mistakes
- Putting
awaitin a plain arrow and being surprised that even the code before it does not run: this is a parse error, not a runtime one. - Forgetting that an
asyncarrow returns a promise and writingconst x = sum(1, 2), which yields aPromiseinstead of a number. - Marking the outer function
asyncwhile usingawaitinside a nested plain callback, for examplearr.forEach(item => { await save(item); }). The callback itself is what needs the keyword:async item => .... - Expecting
arr.forEach(async ...)to wait for every operation:forEachignores the returned promises, so you needfor...ofwithawaitorPromise.all(arr.map(async ...)). - Using top-level await in a file that is loaded as a classic script or as CommonJS, where it is simply not available.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.