π¨ JavaScript Β· Topic 19 of 20
Promises & async/await β JavaScript Questions with Answers
30 practice questions on Promises & async/await, each with the correct answer and a clear explanation of why it is right. Read through them as revision notes, or take this topic as an interactive quiz to test yourself.
0 easy Β· 14 medium Β· 16 hard Β· Part of JavaScript: The language of the web - basics to advanced, 20 topics.
Medium questions (14)
Q1. medium
What is a Promise?
- A An object representing a value that will be available later - a placeholder for an async result
- B A guaranteed return value
- C A type of callback
- D A loop construct
Answer: A β An object representing a value that will be available later - a placeholder for an async result
A promise is a receipt for future data. It lets you attach handlers now for a result that arrives later, avoiding deeply nested callbacks.
PromisesAsync
Q2. medium
What are the three states of a promise?
- A Pending, fulfilled, rejected
- B Start, middle, end
- C Open, closed, error
- D Waiting, running, done
Answer: A β Pending, fulfilled, rejected
A promise begins pending and settles exactly once into fulfilled (with a value) or rejected (with a reason). It can never change again.
Promise states
Q3. medium
How do you handle a promise's SUCCESS value?
fetch(url).then(res => res.json()).then(data => show(data));
const data = await (await fetch(url)).json();
- A .then(value => ...) or await
- B .catch(value => ...)
- C .finally(value => ...)
- D return value
Answer: A β .then(value => ...) or await
then receives the fulfilled value. await unwraps it more readably inside an async function.
thenawait
Q4. medium
How do you handle a promise REJECTION?
- A .catch(err => ...) or try/catch around await
- B .then(err => ...)
- C if (promise.error)
- D Rejections cannot be handled
Answer: A β .catch(err => ...) or try/catch around await
catch handles rejections anywhere earlier in the chain. With await, the rejection is thrown, so a normal try/catch works.
catchError handling
Q5. medium
What does .finally() do?
setLoading(true);
fetchData().then(show).catch(showError).finally(() => setLoading(false));
- A Runs whether the promise fulfilled or rejected - ideal for cleanup
- B Runs only on success
- C Runs only on failure
- D Ends the chain permanently
Answer: A β Runs whether the promise fulfilled or rejected - ideal for cleanup
Perfect for hiding a loading spinner or re-enabling a button. It receives no argument and passes the result through unchanged.
finallyCleanup
Q7. medium
What does an async function ALWAYS return?
async function f() { return 42; }
f().then(v => console.log(v)); // 42
console.log(f()); // Promise { 42 }
- A A promise - even if you return a plain value
- B The value directly
- C undefined
- D A callback
Answer: A β A promise - even if you return a plain value
return 42 inside async produces a promise fulfilled with 42. That is why you must await it or use .then() at the call site.
asyncReturn values
Q8. medium
Where can you use the await keyword?
- A Inside an async function, or at the top level of an ES module
- B Anywhere
- C Only inside loops
- D Only in the browser
Answer: A β Inside an async function, or at the top level of an ES module
Using await in a regular function is a SyntaxError. Top-level await works in ES modules (type="module"), not in classic scripts.
awaitasyncModules
Q11. medium
What does Promise.all([p1, p2]) do?
- A Waits for ALL to fulfil and gives an array of results - but rejects immediately if ANY rejects
- B Waits for the first one
- C Runs them one after another
- D Ignores rejections
Answer: A β Waits for ALL to fulfil and gives an array of results - but rejects immediately if ANY rejects
It is all-or-nothing: one failure rejects the whole thing (the others still run but their results are discarded). Use allSettled when partial success is acceptable.
Promise.allConcurrency
Q15. medium
What does each .then() in a chain return?
fetch(url)
.then(res => res.json()) // returns a promise - awaited
.then(data => data.items) // plain value
.then(items => show(items));
- A A NEW promise resolved with the callback's return value - which is why chaining works
- B The original promise
- C undefined
- D The raw value
Answer: A β A NEW promise resolved with the callback's return value - which is why chaining works
Returning a value passes it to the next then; returning a PROMISE waits for it to settle first, flattening the chain automatically.
Chainingthen
Q18. medium
How do you catch an error from an awaited promise?
try {
const data = await getData();
} catch (err) {
showError(err);
}
- A Wrap the await in try/catch
- B Use .then only
- C Errors cannot be caught with await
- D Use if (error)
Answer: A β Wrap the await in try/catch
await converts rejection into a thrown error, so ordinary try/catch/finally works - one of the main readability wins of async/await.
try/catchawait
Q21. medium
How do you run async operations SEQUENTIALLY?
- A A for...of loop with await inside
- B forEach with await
- C Promise.all
- D map with await
Answer: A β A for...of loop with await inside
for...of respects await, pausing each iteration until the operation completes - necessary when each step depends on the previous or you must not overload a server.
for...ofSequential
Q23. medium
What does Promise.resolve(5) create?
- A A promise already fulfilled with 5
- B A pending promise
- C The number 5
- D A rejected promise
Answer: A β A promise already fulfilled with 5
Useful for returning a promise from a function that sometimes has a cached value, so callers can always use .then/await consistently.
Promise.resolve
Q26. medium
Why must you await response.json() after fetch?
const res = await fetch(url);
const data = await res.json();
- A Reading and parsing the body is itself asynchronous, so json() returns a promise
- B It is optional
- C To convert to a string
- D fetch is synchronous
Answer: A β Reading and parsing the body is itself asynchronous, so json() returns a promise
fetch resolves once the HEADERS arrive; the body may still be streaming. Hence the classic two awaits.
fetchjson
Q29. medium
Can a promise change state twice?
- A No - it settles once; later resolve/reject calls are ignored
- B Yes, any number of times
- C Only from rejected to fulfilled
- D Only with .then
Answer: A β No - it settles once; later resolve/reject calls are ignored
Immutability once settled makes promises predictable: every handler attached (before or after) sees the same single outcome.
Promise states
Hard questions (16)
Q6. hard
How do you create a promise manually?
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
- A new Promise((resolve, reject) => { ... })
- B Promise.create()
- C promise()
- D new Async()
Answer: A β new Promise((resolve, reject) => { ... })
The executor runs immediately; call resolve(value) on success or reject(error) on failure. Mainly used to wrap old callback APIs.
Promise constructor
Q9. hard
What is the output ORDER?
async function f() {
console.log("1");
await null;
console.log("2");
}
f();
console.log("3");
- A 1 3 2 - code before await runs synchronously; the rest resumes as a microtask
- B 1 2 3
- C 3 1 2
- D 1 3, then 2 never runs
Answer: A β 1 3 2 - code before await runs synchronously; the rest resumes as a microtask
An async function starts executing immediately and only pauses AT the first await, returning control to the caller. Awaiting even a non-promise defers the remainder.
asyncEvent loop
Q10. hard
What is wrong with this sequential code?
const a = await fetchA();
const b = await fetchB();
const [a, b] = await Promise.all([fetchA(), fetchB()]);
- A If they are independent, this wastes time - B only starts after A finishes. Use Promise.all
- B It is a syntax error
- C await cannot be used twice
- D Nothing is wrong
Answer: A β If they are independent, this wastes time - B only starts after A finishes. Use Promise.all
Sequential awaits are correct when B needs A's result, but wasteful otherwise. Promise.all runs them concurrently, roughly halving the wait.
Promise.allPerformance
Q12. hard
How is Promise.allSettled different from Promise.all?
const results = await Promise.allSettled(promises);
results.forEach(r => r.status === "fulfilled" ? ok(r.value) : bad(r.reason));
- A It NEVER rejects - it waits for all and returns each result as {status, value|reason}
- B It is faster
- C It returns only successes
- D It stops at the first rejection
Answer: A β It NEVER rejects - it waits for all and returns each result as {status, value|reason}
Ideal when you want every outcome, e.g. uploading ten files and reporting which succeeded and which failed.
allSettled
Q13. hard
What does Promise.race([p1, p2]) return?
const timeout = ms => new Promise((_, rej) => setTimeout(() => rej(new Error("timeout")), ms));
await Promise.race([fetch(url), timeout(5000)]);
- A The result of whichever settles FIRST - fulfilled or rejected
- B The fastest successful one only
- C All results
- D The slowest one
Answer: A β The result of whichever settles FIRST - fulfilled or rejected
Commonly used for timeouts: race the real request against a promise that rejects after N seconds.
Promise.raceTimeouts
Q14. hard
What does Promise.any() do?
- A Fulfils with the FIRST successful promise, ignoring rejections (fails only if all fail)
- B Same as race
- C Same as all
- D Returns any random one
Answer: A β Fulfils with the FIRST successful promise, ignoring rejections (fails only if all fail)
Unlike race (which settles on the first result even if it is an error), any keeps waiting for a success - useful for querying several mirrors.
Promise.anyPromise.race
Q16. hard
What is the output?
Promise.resolve(1)
.then(v => { console.log(v); })
.then(v => console.log(v));
.then(v => { return v; }) // or just .then(v => v)
- A 1 then undefined - the first then returned nothing
- B 1 then 1
- C 1 only
- D undefined twice
Answer: A β 1 then undefined - the first then returned nothing
Forgetting to RETURN inside a then breaks the value chain - the next handler receives undefined. A very common bug.
ChainingReturn values
Q17. hard
Where does an error thrown inside a .then() go?
- A To the nearest .catch() LATER in the chain
- B To the surrounding try/catch
- C It is silently ignored
- D It crashes the browser
Answer: A β To the nearest .catch() LATER in the chain
Rejections skip subsequent then handlers until a catch is found. Note a catch placed BEFORE the throwing then cannot catch it - order matters.
Error propagationcatch
Q19. hard
What is an unhandled promise rejection?
- A A rejected promise with no catch handler - it logs a warning and can terminate Node processes
- B A promise that stays pending
- C A syntax error
- D A fulfilled promise
Answer: A β A rejected promise with no catch handler - it logs a warning and can terminate Node processes
Always end chains with .catch() or wrap awaits in try/catch. A global fallback: window.addEventListener('unhandledrejection', ...).
Error handlingNode.js
Q20. hard
What is wrong with using await inside forEach?
items.forEach(async (i) => { await save(i); });
for (const i of items) await save(i); // sequential
await Promise.all(items.map(i => save(i))); // concurrent
- A forEach ignores the returned promises, so the code continues without waiting
- B It is a syntax error
- C async cannot be used in callbacks
- D Nothing is wrong
Answer: A β forEach ignores the returned promises, so the code continues without waiting
forEach discards return values, so nothing awaits the saves. Use a for...of loop for sequential work, or Promise.all(items.map(...)) for concurrent work.
- A very common async bug in real projects.
forEachAsync loops
Q22. hard
What is the output?
async function f() { throw new Error("boom"); }
f().catch(e => console.log(e.message));
- A boom - throwing inside async REJECTS the returned promise
- B An uncaught error
- C Nothing
- D SyntaxError
Answer: A β boom - throwing inside async REJECTS the returned promise
Async functions convert throws into rejections, which is why try/catch and .catch() are interchangeable ways to handle them.
asyncRejection
Q24. hard
Can you await a NON-promise value?
const x = await 5;
- A Yes - it is wrapped in a resolved promise, though it still defers the rest of the function
- B No, it throws
- C It returns undefined
- D It blocks forever
Answer: A β Yes - it is wrapped in a resolved promise, though it still defers the rest of the function
await accepts any value. This is handy when a function might return either a value or a promise - and it explains why 'await null' still yields to the event loop.
awaitThenable
Q25. hard
What is the output ORDER?
console.log("A");
(async () => { console.log("B"); await 0; console.log("C"); })();
console.log("D");
- A A B D C
- B A B C D
- C A D B C
- D B A D C
Answer: A β A B D C
The async function body starts synchronously (B), pauses at await, control returns to the caller (D), then the continuation runs as a microtask (C).
asyncMicrotasks
Q27. hard
What is the promisify pattern?
const getPos = () => new Promise((res, rej) =>
navigator.geolocation.getCurrentPosition(res, rej));
const pos = await getPos();
- A Wrapping a callback-based API in a promise so it can be awaited
- B Converting promises to callbacks
- C Making code synchronous
- D A testing technique
Answer: A β Wrapping a callback-based API in a promise so it can be awaited
Legacy APIs (older Node functions, geolocation, some libraries) take callbacks. Wrapping them once lets the rest of your code use async/await.
PromisifyLegacy APIs
Q28. hard
Does creating a promise start its work lazily or immediately?
- A Immediately - the executor runs as soon as the promise is created, even before .then is attached
- B Only when .then is called
- C Only when awaited
- D Never automatically
Answer: A β Immediately - the executor runs as soon as the promise is created, even before .then is attached
Promises are EAGER. const p = fetch(url) starts the request at once; awaiting later just waits for the already-running work. This is why Promise.all(fns.map(f => f())) runs concurrently.
Eager evaluation
Q30. hard
What is the practical difference between .then chains and async/await?
- A They are equivalent - await is syntax over promises, usually more readable for sequential logic
- B await is faster
- C then is deprecated
- D await avoids promises entirely
Answer: A β They are equivalent - await is syntax over promises, usually more readable for sequential logic
Use await for step-by-step flows and try/catch; use .then when composing pipelines or with combinators like Promise.all. Mixing both is fine.
async/awaitthen