What is a Promise?

A promise is a placeholder for the result of an asynchronous operation. That’s it. JavaScript Promises may seem like a very complicated concept, but they are not. A promise is just placeholder.

Why do Promises Exist?

Promises make flow-control easy to manage. The more complex an application gets, the more difficult flow control becomes. Before promises, event-driven patterns like pub/sub were popularized. They have their place and will remain popular. But event driven architecture is reliant upon event handlers being bound prior to an event occurring. If for instance a button were clicked before a click handler was bound, nothing would happen. This is a problem that promises solve.

But before you think that you should change everything to a promise, wait. You should not. Event driven architecture is extremely helpful for simple user interaction. Where event driven architecture becomes problematic is complex systems/network interaction.

When Node.js was created, it solved this problem with the callback pattern. In the callback pattern you don’t have to worry about event handlers being registered before an event is triggered because the handlers are passed as arguments – callback arguments. The callback pattern makes chaining multiple [callback] functions throughout the flow of a program simple. But that simplicity can quickly become a nightmare – just Google “callback hell” for the pitfalls of the callback pattern.

So back to the question, why do promises exist? JavaScript needed a better way to manage flow control. Ahhhhh, we’ve come full circle.

What Happens in a Promise?

First, let’s remember what a promise is: a promise is a placeholder. When a promise is explicitly assigned via the Promise() constructor, or implicitly returned from a method like fetch(), what is actually returned from either scenario is just an object. The returned object’s __proto__ property points to Promise. So, we call it a “Promise Object”. But do remember that it’s just an object. If you look through the prototype chain shown in the screenshot below, you’ll see just one level up that the __proto__ property points to Object.

Basic JavaScript Promise
Basic JavaScript Promise

Okay, moving on. The promise object that is returned contains an internal [[PromiseStatus]] property. There are three status values that this property can have, which together comprise the “Promise Life Cycle”. Those statuses are:

  • "pending": this is the first status. It indicates the underlying operation has not completed. A promise will always have a pending status at some point in its life cycle.

  • "fulfilled": this status indicates that the underlying operation has successfully completed.

  • "rejected": this status indicates that the underlying operation did not complete. This may be due to a bug, network issue, etc.

Again, those are the statuses that comprise the life cycle of a promise in JavaScript.

Let’s talk about the state of a promise. State in promises is very simple, it’s either settled or unsettled. When a promise’s status is "pending", its state is unsettled. When a promise’s status is "fulfilled" or "rejected", its state is settled. Simple when it’s not over complicated, huh?

Let’s Review Promises

  • A promise is a placeholder for the result of an asynchronous operation.
  • Promises make flow-control easy to manage.
  • Promises have three statuses that comprise their life cycle: pending, fulfilled, and rejected.
  • Promises have two states: settled and unsettled.

Final Word on Promises

I’ve seen/read/viewed a lot of people who use the terms “status” and “state” loosely – even interchangeably at times. This causes a lot of confusion.

Understanding the difference between “status”, “state”, and “life cycle” is critical to understanding promises. Conflating these terms is one of the main reasons promises seem so confusing. Understand them, and you are well positioned to mastering promises.

Posted by: John Dugan