A Brief history of promises

I Promise.

i promise, a brief history of the promise .. i promise

Promises are older than you think - they originate from an idea born during the start of the space race. I want to tell you a story of how a concept from the 1960s made its way into your JS runtime.

sync and async

Before we begin, it is important that we establish the difference between sync actions and async actions. Now, we could talk about code and implementation details, but I find an analogy to be better suited for this task.

driving a car, cars driving across the image

If you frame the world and everything that we do as us interacting with an asynchronous entity the distinction becomes easier to reason about. Picture yourself driving a car down the road: you are listening to the radio, staying in your lane, and carrying on a conversation with the passenger next to you. Now you feel the urge to sneeze, and as we all know sneezing is the last thing you want to be doing when you are driving. Try as you might you cannot stop yourself from sneezing, and there you go - you sneeze and close your eyes. Everything else you are doing at that moment does not "Stop" - it continues on - but you are stuck in the sneezing state: frozen, eyes shut, driving at 65 miles per hour.

Sneezing is what I would call a synchronous real world action: when you are sneezing nothing else matters because THAT IS ALL YOU ARE DOING.

#include <stdio.h>
                    int main()
                    {
                        printf(

Let me illustrate the point in code. Here you can see we print "hello", sleep for a while and then print "bye". While we are asleep nothing else is going on in the program, it is just sitting there, waiting - doing nothing else. When the process completes we continue on with our program. The Important thing to take away here is the fact that while we are asleep, NOTHING is happening in our program, Nothing can happen at all given this paradigm. This is an important concept to keep in mind as we wander onto this winding and murky async history path.

devtools showing a native Promise when printed to the screen

Opening our browser console today and typing Promise, we are greeted by a Promise constructor. We can resolve this promise with our friend the horse, and we can reject a promise with some fire.

can i use support for Promise, showing almost all green

And no this is not just nightly Chrome, this is a very very well supported API, that you can use today without polyfills and without vendor scripts in both the browser and in Node.

So you are thinking of course Sam, tell me something I do not already know jesh. But I want to point out that being able to use this API is not the novel thing, the novel thing is asking yourself Why can I do this today?

why can i do this today?

How did these 7 letters ("Promise") get joined together so precariously and yield such a useful and powerful thing?

ryan dahl original node.js presentation 2009

Ryan Dahl first presented Node.js in 2009, which as you know was one of the biggest shifts in JavaScript development since Brendan Eich wrote the initial implementation of JavaScript. In his presentation at JSConf, this early version version of Node had Promises… well at least what they called "Promises"... Of course I wanted to find out exactly what this implementation looked like so I cloned the Node.js repo to take a look at the logs (FAIR WARNING - this repo is kinda big and it took 30 minutes :( so I do not really recommend that you do it)

original nodejs github commit for promises

Looking at the repo we can see that in June 2009 the initial commit was landed for Promises… let's go one step further and see how it was implemented.

original nodejs promise implementation using event emitters

Oh, here it is. Wait though… this is not a promise implementation, this is just an event emitter wrapped up in a promise-like interface. But what was the intent and where did this idea come from?

where did this come from?

What is the lineage of this idea of a promise?

timeline showing the different promise implementations

It was pretty tricky, however through the extensive use of wayback machine, emails, and personal interviews I was able to piece together a reasonable history all the way from the early origins of Promises to the ES2015 spec.

mercury space program 1961

To set the scene, this tale of the promises starts in 1961. In 1961, NASA was busy with the Mercury space program, racing into space to catch up to Russia after their somewhat surprise launch of Sputnik 1. Ham the chimp had just returned from a successful trip into space, and was on the cover of LIFE.

Ok… enough with Ham the chimp. Back to Promises we go…

algol thunks, 1961

In 61, along came a paper written about Algol - short for algorithmic language - and was published in ACM. This paper described a method of compiling procedural statements. I won't bore you with the details because I know everyone in the room here is super familiar with algol already, but the important concept discussed in this paper comes down to this idea of a "Thunk"

a thunk is a piece of coding which priceds an address. when executed, it leaves in some standard location

A thunk is a compile time optimization which provides an address. When this thunk is executed, some value will eventually be available at some standard location (or at the given address). Now why is this important and what does this mean? This "thunk" thing is the concept that a value reference will eventually be stored in a given location at some time in the future. This should sound somewhat familiar to the basic idea of a promise -- a value that will eventually represent some value in the future.

1977 star wars box office

If we hop into the Delorean and fast forward to 1977, the first Star Wars had just been released and an equally important concept was introduced. A paper outlining the concept of a "future" was published.

futures 1977

While this paper was about approaches for dealing with garbage collection, it has a few novel ideas that drove inspiration for future iterations on the concept of eventual values, and remote execution of functions.

...allows the fully parallel evaluation of arguments to a function

In the paper abstract right away the author throws out this concept of a parallel evaluation of arguments to a function. This idea in the JavaScript world is nothing new this actually feels like a pretty recognizable concept. We want to eval multiple things at the same time and in parallel. Much like a webworker allows us to do… The notable thing is that this is in 1977, not 2016.

in call-by-future, each format parameter of a function is bound to a seperate function (called a future)

The paper goes further and outlines the approach of taking each of the params and binding them to a separate process. Here in lies the essential concept, as soon as we allow individual params to be handled by different processes there is nothing holding back the evaluation and running of each of params values" in parallel and in a way that does not block each other. Now if you are like me, you are thinking why do I care about params, those are just values… however if you shift your perception of values to something different -- think of params here as not just flat values but potentially other functions and other "eventual" values.

joule channels, channels are message plumbing to connect servers, a joule computation is a dataflow diagram spread out in space, 1995

In 1995, the Joule language was introduced, intended to be a new model for building distributed systems. The entire model was that of a making building distributed systems simple. Every action in Joule consisted of sending and receiving messages from servers. A "channel" was the abstraction or message plumbing through which the messages are conveyed. It was in this way that Joule set the stage for a formal message pattern. This idea of a middleman or relay entity that was responsible for delegating async communication instead of an event based pattern meant that the data and its flow was predictable, which allowed you to treat these entities as just another pattern for passing data around, even though they were async under the hood.

e lang, first non-blocking promise impl - 1997

The culmination of these ideas and the true watershed moment which inspired the majority of Future/Promise implementations is in E. While E introduced many concepts, we will only look at a specific subset of the language - the Promise implementation. E was the first implementation of promises that was truly non-blocking, in that the work that was being done "Remotely" would never block the future execution.

diagram showing the relationship between resolved and broken state of a promise

E also established a lexicon, shown in the diagram above. With a few minor wording adjustments, this diagram maps 1:1 to what JavaScript promises are today. This diagram comes from the original E language paper and description by Mark Miller. You will note that it treats local promises and remote promises as the same thing, just as Joule treated all messages as "channels" and futures were potentially going to enable the fully parallel execution across multiple processes. E builds on these ideas and treats the idea of a Promise as agnostic to where the work is actually being done. A last interesting note about this original design is that while the original name for a promise in a failed state was "broken", which was fine in other languages, this would not work in JavaScript… why not? "broken" => break … break is a reserved word in JS… so this was changed to .catch() instead.

python twisted deferred, attended to mirror E promises- 2001

Python's Twisted framework directly derived their future/deferred implementation From the E language. This implementation, while not capturing the entire idea of E's promises, brought along enough of the concepts to be the seed from which the JS implementations grew.

the grand JS port

From this point forward we will be following the JavaScript track of the story - it is important to note however that the implementation path in other languages was running in parallel and in some ways was more "correct" during this time period.

twisted to MochiKit 2005

The first implementation in JS that I could find that followed the ethos of E promises was found in MochiKit. MochiKit (extracted from MochiBot) by Bob Ippolito, was a direct port from Twisted. When I reached out to Bob asking where he got the idea for this implementation he noted that he directly ported the implementation from Python's Twisted lib.

What I find so perfect about our communication is the rationale for why he ported this functionality (since it really has stood the test of time)

MochiBot used a lot of AJAX style calls and Deferred made that much easier to work with than directly using XMLHTTPREQUEST

And as he pointed out…

It can't have been that bad of an idea since today's fetch API provides a HTTP interface that returns a promise.

Keep in mind this was in 2005… this async problem that to this day is troublesome was being felt and dealt with before I even started seriously programming.

dojo deferredRequest 2006

In 2006 (or perhaps earlier since I think the commit date is lying about the date due to the bulk import from SVN), the Dojo Toolkit team checked in deferredRequest. So I guess in this case Dojo did not do it first ;)... But they did do it quite early.

dojo deferred 2007

Further searching of the underbelly of the internet yielded additional interesting finds in Dojo land. In 2007 Alex Russell decoupled the Deferred idea from deferredRequest. In a listserve post from 2006 Alex also mentioned the inspiration for the deferred request as coming from Mochikit and Python's Twisted implementation.

waterken Q - early 2009

Early 2009 was the moment where promise adoption to surged, going from niche to mainstream. While Q may be somewhat familiar to you, there was an earlier version called Waterken Q that has a lot of syntax familiarity with newer libs like modern Q and when.js. The implementation self identified as a "concise and expressive API for interacting with JSON resources"

promise proposal - march 24 2009

In 2009 Kris Zyp proposed adding Promises as an official API in the CommonJS mailing this. To many this was the start of Promises landing in the spec. In his post he notes the influences of Waterken Q.

The Q awakening september 3 2009

In September of 2009 Kris Kowal (also on the Promise API thread) took the ideas of waterken Q along with the design and goals of E to create the popular Q lib.

dojo deferred to promise naming - september 17 2009

8 days later, Dojo began the conversation to go from the idea of a deferred to the idea of a Promise.

the rise of JQuery 2010

In December of 2010, deferreds landed in jQuery core, but were not yet exposed externally as an API. The promise interface was eventually exposed in the $.ajax API - anyone programming JavaScript at the time most likely has this burned into their memory.

github commit adding promises to jquery core 2010

This simple API single-handedly papered over the friction of XMLHttpRequest, at the same time introducing the concept of "eventual resolution" as a happy side-effect.

$.ajax().done()

Keep in mind during this time the web was rapidly moving forward, HTML5 was coming and more and more new web APIs were shipping: Webcrypto, fetch, IndexedDB, localStorage. Each of these APIs had to figure out what to do regarding asynchronous actions. Some opted to use promise-like interfaces, others callbacks, and some event emitters. This disconnect became especially complicated when different promise implementations were added to the mix.

briar patch of apis

The promises spec was simple but the lack of a unified test suite was making different implementations not work together. Paul Chavard lead the way with the idea of introducing a test suite for Promise contract fulfillment. Paul created a pull request to Ember to introduce a Promise test suite.

Domenic Denicola, recognizing the shortcomings of the implementation, went ahead and created the A+ promise doc and test suite the day that the Ember PR landed. (hear him tell the story here).

an A+ unification
50+ A+ implementations

This test suite and spec lead to 50+ compatible Promise implementations, a massive win for the community since it meant that you did not have to worry about different async / deferred / promise implementations. So long as the implementation was A+ you knew that they would be compatible at the .then level. The meta win here was the fact that having multiple agreeing implementations showed the TC39 that there was community consensus around the idea of Promises… an idea that a few years earlier was thought to be too esoteric for common use.

promises landed in es2015 by tc39 - 2015

Because of the community buy-in and eventual need for other async operations like module loading in ES2015 (called ES6 at the time), Promises were fast-tracked and landed, with much thanks to Domenic Denicola.

So here we are in 2020 using an API that is the composite of ideas and work starting in 1961, spanning multiple programming languages and generations.


Special thanks to Kris Kowal, Mark Miller, Rebecca Murphey, Alex Russell, and Domenic Denicola for their help in reconstructing this timeline. Additional thanks to Karl Horky for the editing help.


Sam Saccone @samccone