What states can a promise be in, and how do you move between them?
A promise starts in the pending state. It then settles, and settling means moving to exactly one of two final states: fulfilled if it was resolved with a value, or rejected if it was rejected with a reason. Once it has settled it stays in that state forever.
const promise = new Promise((resolve, reject) => {
resolve("done");
});
promise.then((value) => console.log("fulfilled:", value));
promise.catch((err) => console.log("rejected:", err.message));
// A rejected promise.
const failing = new Promise((resolve, reject) => {
reject(new Error("boom"));
});
failing.catch((err) => console.log("caught:", err.message));The executor function runs immediately and synchronously when the promise is created. That means anything before the first await or before the runtime gets control is not asynchronous, and a long synchronous computation inside the executor blocks the thread just like any other code.
You observe the states with the then method, which takes a success handler and an optional failure handler, and with the catch method, which is just then with the success handler omitted. There is also a finally method, which runs its callback whatever happened, and which is the right place for cleanup such as hiding a loading spinner.
Two details about the handlers. The success handler receives the resolved value, but if that value is itself a promise, the promise machinery waits for it and hands you the inner value instead, which is called unwrapping. And handlers registered with then never run immediately; they are queued as microtasks, so even an already settled promise calls its handler a little later.