JS: Promise Tutorial
(new in ECMAScript 2015)
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
new Promise(executorF)
executorF should be a function that takes 2 args, fResolve, fReject. Both are also functions.
const execF = (fResolve, fReject) => { setTimeout(() => { fResolve("fResolve called"); }, 999); }; const pms = new Promise(execF); pms.then((x) => { // x is whatever we passed in the fResolve() function console.log(x); }); // fResolve called
// define a asynchronous function using Promise object const pms = new Promise((f1, f2) => { f1("f1 called"); }); // call it pms.then((x) => console.log(x)); // prints "f1 called"
States of Promise
A Promise object p is in one of three mutually exclusive states: fulfilled, rejected, and pending:
-
p is fulfilled if
p.then(f, r)will immediately enqueue a Job to call the functionf. -
p is rejected if
p.then(f, r)will immediately enqueue a Job to call the functionr. - p is pending if it is neither fulfilled nor rejected.
p is settled if it is not pending.
- A promise is resolved if it is settled or if it has been “locked in” to match the state of another promise.
- Attempting to resolve or reject a resolved promise has no effect.
- An unresolved promise is always in the pending state.
- A resolved promise may be pending, fulfilled or rejected.
Properties
Promise.all
Promise.race
Promise.reject
Promise.resolve
Promise.prototype
Promise.prototype.constructor
Promise.prototype.catch
Promise.prototype.then
JavaScript Promises Tutorial (ai generated)
JavaScript Promises Tutorial
Promises are one of the most important features in modern JavaScript for handling asynchronous code. They represent the eventual completion (or failure) of an async operation and its resulting value.
Why Promises?
Before Promises, we used callbacks. This led to "callback hell":
getData(function(result) { process(result, function(processed) { save(processed, function() { console.log("Done"); }); }); });
Promises make async code more readable, chainable, and easier to handle errors.
What is a Promise?
A Promise is an object that has three states:
- pending: initial state (neither fulfilled nor rejected)
- fulfilled: operation completed successfully
- rejected: operation failed
Once a promise is fulfilled or rejected, it stays in that state (immutable).
Creating a Promise
const myPromise = new Promise((resolve, reject) => { // async operation here const success = true; setTimeout(() => { if (success) { resolve("Operation succeeded!"); // fulfill } else { reject(new Error("Operation failed!")); // reject } }, 1000); });
resolve(value)→ fulfills the promise-
reject(reason)→ rejects the promise (usually pass anErrorobject)
Consuming a Promise
Use .then(), .catch(), and .finally():
myPromise .then((result) => { console.log("Success:", result); }) .catch((error) => { console.error("Error:", error.message); }) .finally(() => { console.log("This runs no matter what"); });
You can also use the modern async/await syntax (recommended for most code):
async function run() { try { const result = await myPromise; console.log("Success:", result); } catch (error) { console.error("Error:", error.message); } finally { console.log("Cleanup"); } } run();
Chaining Promises
This is where Promises shine:
function fetchUser(id) { return new Promise(resolve => { setTimeout(() => resolve({ id, name: "Xah" }), 500); }); } function fetchPosts(userId) { return new Promise(resolve => { setTimeout(() => resolve(["Post1", "Post2"]), 500); }); } fetchUser(1) .then(user => { console.log("User:", user); return fetchPosts(user.id); // return another promise }) .then(posts => { console.log("Posts:", posts); }) .catch(err => console.error(err));
Each .then() receives the resolved value from the previous promise.
Promise Static Methods
| Method | Description | Use Case |
|---|---|---|
Promise.all() |
Wait for all promises to resolve | Multiple parallel requests |
Promise.allSettled() |
Wait for all to settle (fulfilled or rejected) | When you want all results |
Promise.race() |
First promise to settle wins | Timeout / fastest response |
Promise.any() |
First promise to fulfill | First successful response |
Promise.resolve() |
Create already resolved promise | Quick values |
Promise.reject() |
Create already rejected promise | Quick errors |
Examples
// 1. Promise.all const promises = [ fetchUser(1), fetchPosts(1), Promise.resolve("static") ]; Promise.all(promises) .then(results => console.log(results)) .catch(err => console.error("One failed:", err)); // 2. Promise.race with timeout function timeout(ms) { return new Promise((_, reject) => setTimeout(() => reject("Timeout"), ms)); } Promise.race([fetchUser(1), timeout(100)]) .then(user => console.log("Got user fast")) .catch(err => console.log(err));
Error Handling Best Practices
-
Always use
.catch()ortry/catchwithawait - Reject with real
Errorobjects (not strings) - Use
.finally()for cleanup - Avoid mixing callbacks and promises
Common pattern:
async function safeFetch(url) { try { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); return await res.json(); } catch (err) { console.error("Fetch failed:", err); throw err; // re-throw if caller needs to handle } }
Converting Callbacks to Promises
// Old callback style function oldAPI(callback) { setTimeout(() => callback(null, "data"), 1000); } // Modern const promiseAPI = () => new Promise((resolve, reject) => { oldAPI((err, data) => { if (err) reject(err); else resolve(data); }); });
Many libraries already provide promise versions (fs.promises, util.promisify()).
Real-World Example: Fetch API
async function getUserData(username) { try { const response = await fetch(`https://api.github.com/users/${username}`); if (!response.ok) throw new Error("User not found"); const user = await response.json(); console.log(user); return user; } catch (error) { console.error("Failed to fetch user:", error); } } getUserData("xah_lee");
Key Rules to Remember
- A promise can only be resolved or rejected once
.then()always returns a new promise-
Throwing inside
.then()orawaitrejects the promise asyncfunctions always return a promise
Practice Exercises
- Create a promise that resolves after 2 seconds with your name.
- Chain 3 promises that each add 1 to a number.
- Use
Promise.allto load 3 different fake API calls. - Implement a timeout wrapper for any promise.
Would you like me to expand any section (e.g., more advanced patterns, microtasks, or a full project example with loading states)? Just ask!