Imagine this scenario: I walk up to the counter at a fast-food restaurant, and place an order for a cheeseburger. I hand the cashier $2.47. By placing my order and paying for it, I’ve made a request for a value back (the cheeseburger). I’ve started a transaction. But often, the chesseburger is not immediately available for me. The cashier hands me something in place of my cheeseburger: a receipt with an order number on it. This order number is an IOU (“I owe you”) promise that ensures that eventually, I should receive my cheeseburger. So I hold onto my receipt and order number. I know it represents my future cheeseburger, so I don’t need to worry about it anymore — aside from being hungry! While I wait, I can do other things, like send a text message to a friend that says, “Hey, can you come join me for lunch? I’m going to eat a cheeseburger.” I am reasoning about my future cheeseburger already, even though I don’t have it in my hands yet. My brain is able to do this because it’s treating the order number as a placeholder for the cheeseburger. The placeholder essentially makes the value time independent. It’s a future value. Eventually, I hear, “Order 113!” and I gleefully walk back up to the counter with receipt in hand. I hand my receipt to the cashier, and I take my cheeseburger in return. In other words, once my future value was ready, I exchanged my value-promise for the value itself. But there’s another possible outcome. They call my order number, but when I go to retrieve my cheeseburger, the cashier regretfully informs me, “I’m sorry, but we appear to be all out of cheeseburgers.” Setting aside the customer frustration of this scenario for a moment, we can see an important characteristic of future values: they can either indicate a success or failure. Every time I order a cheeseburger, I know that I’ll either get a cheeseburger eventually, or I’ll get the sad news of the cheeseburger shortage, and I’ll have to figure out something else to eat for lunch.
Because Promises encapsulate the time-dependent state — waiting on the fulfillment or rejection of the underlying value from the outside, the Promise itself is time-independent, and thus Promises can be composed (combined) in predictable ways regardless of the timing or outcome underneath. Moreover, once a Promise is resolved, it stays that way forever — it becomes an immutable value at that point — and can
then be observed as many times as necessary. Note: Because a Promise is externally immutable once resolved, it’s now safe to pass that value around to any party and know that it cannot be modified accidentally or maliciously. This is especially true in relation to multiple parties observing the resolution of a Promise. It is not possible for one party to affect another party’s ability to observe Promise resolution.
Immutability may sound like an academic topic, but it’s actually one of the most fundamental and important aspects of Promise design, and shouldn’t be casually passed over.
That’s one of the most powerful and important concepts to understand about Promises. With a fair amount of work, you could ad hoc create the same effects with nothing but ugly callback composition, but that’s not really an effective strategy, especially because you have to do it over and over again. Promises are an easily repeatable mechanism for encapsulating and composing future values.