Loading...

JavaScript Promises

The cup is a paragraph, #cup. It starts as blank, and the script sets it to waiting before it asks for tea.
pour does not hand back the drink. It hands back a promise. You ask that promise, with then, to write the drink later. The line under pour still says waiting. The line reads waiting / lida tea.

Not the cup you just served

The previous page passed done into serve. serve called it before returning, so the log underneath was already lida tea / poured. Nothing on that page waited.
Here the function you pass to then does not run on the next line. pour returns first. The drink shows up after this script has finished.

Three states

A promise is pending until it settles. resolve fulfills it with a value. reject rejects it with a reason. then runs only for a fulfillment. catch runs only for a rejection. This page’s kettle has no timer. The executor calls resolve or reject immediately, and the handlers still wait until the script ends.

📊 Three states

State What you see Easy to mix up
pending the cup still says waiting the drink is already on the cup
fulfilled then receives lida tea catch runs as well
rejected catch receives no leaves then receives the drink

The executor is now, the handler is not

The function you give new Promise runs at once. That is why resolve("lida tea") can happen before pour returns. The function you give then is different. It is queued. The line after pour(...) still runs while the cup says waiting.

The next line is still waiting

pour("lida") stores a promise in order. The cup was set to waiting. The log is that word, not the drink.

The cup is still waiting

javascript
function pour(order) {
return new Promise(function (resolve, reject) {
if (order === "") {
reject("no leaves");
return;
}
resolve(order + " tea");
});
}
let cup = document.getElementById("cup");
cup.textContent = "waiting";
let order = pour("lida");
console.log(cup.textContent);

The log is waiting. order is the promise. It is not the string lida tea.

then receives the drink

Call then with a function. That function gets the value passed to resolve. It writes the drink and logs it. This log is not the one on the next line. It is the one inside then.

then writes the drink

javascript
function pour(order) {
return new Promise(function (resolve, reject) {
if (order === "") {
reject("no leaves");
return;
}
resolve(order + " tea");
});
}
let cup = document.getElementById("cup");
pour("lida").then(function (drink) {
cup.textContent = drink;
console.log(cup.textContent);
});

The log is lida tea. An empty string never reaches this handler.

No leaves

pour("") calls reject("no leaves") and returns. catch receives that reason. then does not run.

Catch an empty order

javascript
function pour(order) {
return new Promise(function (resolve, reject) {
if (order === "") {
reject("no leaves");
return;
}
resolve(order + " tea");
});
}
pour("").catch(function (reason) {
console.log(reason);
});

The log is no leaves.

The promise is not the drink

order.then is a function. That is how you know order is a promise and not the string you wanted. Comparing the promise to "lida tea" would be false, and this snippet only prints the type of then.

then is a function

javascript
function pour(order) {
return new Promise(function (resolve, reject) {
if (order === "") {
reject("no leaves");
return;
}
resolve(order + " tea");
});
}
let order = pour("lida");
console.log(typeof order.then);

The log is function.

The line under the cup

The script sets the cup to waiting and pushes that word at once. then pushes lida tea and joins the two words. The join is inside then, so it happens after the script, not on the next line.

Page demo — a promised cup

html
<!DOCTYPE html>
<html>
<head>
<title>promised-cup — page</title>
</head>
<body>
<p id="cup">blank</p>
<p id="line">…</p>
<script>
function pour(order) {
return new Promise(function (resolve, reject) {
if (order === "") {
reject("no leaves");
return;
}
resolve(order + " tea");
});
}
let cup = document.getElementById("cup");
let seen = [];
cup.textContent = "waiting";
seen.push(cup.textContent);
pour("lida").then(function (drink) {
seen.push(drink);
cup.textContent = drink;
document.getElementById("line").textContent = seen.join(" / ");
});
</script>
</body>
</html>

The line reads waiting / lida tea. Waiting was immediate. lida tea arrived in then. The word blank is gone. lida tea / poured is the previous page.

At the counter

  1. Set the cup to waiting, call pour("lida"), and log the cup at once. The log is waiting.
  2. Put the drink on the cup inside then. That log is lida tea.
  3. Call pour("") and catch the reason. The log is no leaves.
  4. Read typeof order.then. The log is function.
  5. Read the page line: waiting / lida tea.

Misses at the counter

The cup says waiting until then runs. It does not say poured.

  • Expecting the log under pour to be lida tea
  • Treating the return value as the drink string
  • Using then for an empty order and missing no leaves
  • Using catch for lida and expecting no leaves
  • Reading the line as lida tea / poured

Keep this

  • pour returns a promise, not the string lida tea
  • The next line still logs waiting
  • then receives lida tea after this script
  • An empty order rejects with no leaves, and catch logs it
  • The page line reads waiting / lida tea

🧠 Test Your Knowledge

Ready to Start

Test Your Knowledge

Challenge yourself with this interactive quiz and see how well you understand the topic

❓
5
Questions
🎯
70%
To Pass
♾️
∞
Time
🔄
∞
Attempts

📝 Instructions

  • Read each question carefully
  • Select the best answer for each question
  • You can retake the quiz as many times as you want
  • Your progress will be shown at the top