Promises
- Summary
-
Discussion
- Why do we need promises?
- What are the essentials of a promise?
- What are the states and rules of transition of a promise object?
- What are the methods of a promise object?
- Could you share some details of the then method?
- Can you give some use cases where promises might simplify my code?
- What are some tools for working with promises?
- Can you give some tips for developers coding promises?
- I have a bunch of promises I wish to call sequentially. Can I use a for loop?
- Milestones
- Sample Code
- References
- Further Reading
- Article Stats
- Cite As
In asynchronous programming, it's common practice to use callbacks so that the main thread can continue with other processing rather than wait for current function to complete. When that function completes, a relevant callback function is called. Writing and maintaining asynchronous code can be difficult. Promises offer a syntax that enables better code structure and flow.
A promise is an object that's returned immediately when an asynchronous call is made even when such a call has not completed. This object is constructed and returned "with the promise" that its contents will be filled in at a later point when the asynchronous call completes. Formally,
A promise represents the eventual result of an asynchronous operation.
Promises have become popular since mid-2010s in the world of JavaScript and web development, although promises are not exclusive to JavaScript.
Discussion
-
Why do we need promises? Asynchronous code often ends up with deeply nested callbacks. Programmers often call this callback hell or pyramid of doom. This happens because in async code we can't return values because such values are not yet ready. Likewise, we can't throw exceptions because there's no one to catch them.
Promises solve this by flattening the program flow. Because each asynchronous call immediately returns with a promise object, this object can then be used to specify the callback functions for both success and failure cases. In particular,
then
method of a promise object allows us to specify the callbacks. This method also returns another promise object, thus facilitating a chain or composition of promises.Asynchronous code written with promises is closer in spirit to how we write synchronous code. In synchronous code, we are used to
return
,throw
andcatch
statements. This functionality was lost in the world of asynchronous callbacks. Essentially,The point of promises is to give us back functional composition and error bubbling in the async world.
-
What are the essentials of a promise? A promise is a first-class object, meaning that it can be copied, passed as arguments or returned from functions. Moreover, a promise is returned even before the result of an async call is ready. This allows us to call methods of the object (such as
then
method) while the async call is still in progress.Callbacks can be specified via the
then
method. Two things are possible when thethen
method is called:- If the async call has already completed (or it could even be a synchronous call), the promise object will invoke the relevant callback immediately.
- If the async call is still pending, the promise object will register the callback but call it later.
In either case,
then
method returns a new promise object and this is important to enable chaining. Multiple callbacks can be added by callingthen
multiple times.Promises also simplify the handling of exceptions. Anytime an exception is thrown it can be handled by a single
catch
method. In fact, thecatch
method is a simplification ofthen
method for exception handling. -
What are the states and rules of transition of a promise object? A promise can be in one of three states:
- pending: This is the initial state.
- fulfilled: This is entered if the execution succeeds. The promise is fulfilled with a value.
- rejected: This is entered if execution fails. Rejection comes with a reason.
A promise that's either fulfilled or rejected is said to be settled. This is an apt term since a promise that's settled is an immutable object. It's value (when fulfilled) or reason (when rejected) cannot change. Immutability is important so that consumers of the promise are prevented from introducing side effects.
A promise is said to be resolved if it's either settled or "locked in" to the state of another promise. Once resolved, any attempt to resolve it again will have no effect on the promise. An unresolved promise, a promise that's not resolved, is in pending state.
-
What are the methods of a promise object? The Promises/A+ standard specifies
then
method to access the eventual value or reason. For interoperability, no other method needs to be specified.However, it's common for other standards or implementations to have other methods. For example, ECMAScript 2015 specifies:
- Methods
all
,race
,reject
andresolve
ofPromise
- Methods
then
,catch
andfinally
of aPromise.prototype
Among the non-standard methods are
Promise.denodeify
,Promise.prototype.done
,Promise.prototype.finally
andPromise.prototype.nodeify
. GuzzleHttp's Promise implementation in PHP provides methodsotherwise
,wait
,getState
andcancel
. Bluebird adds useful methods such asmap
,some
,any
,filter
,reduce
,each
andprops
. - Methods
-
Could you share some details of the then
method?A promise must have a
then
method that accepts two arguments and returns another promise:q = p.then(onFulfilled, onRejected)
, where the following hold true for promisesp
andq
:- Arguments
onFulfilled
andonRejected
are both optional - If
onFulfilled
is a function, it's called once whenp
is fulfilled - If
onRejected
is a function, it's called once whenp
is rejected - Promise
q
is resolved with valuex
if either functiononFulfilled
oronRejected
returnsx
- Promise
q
is rejected with reasone
if either functiononFulfilled
oronRejected
throws an exceptione
- If
onFulfilled
is not a function,q
will be fulfilled with the value ofp
when fulfilled - If
onRejected
is not a function,q
will be rejected with the reason ofp
when rejected
For interoperability, non-promises can be treated as promises if they provide the
then
method, for example, using duck typing. Such an object is called a thenable. - Arguments
-
Can you give some use cases where promises might simplify my code? Promises can enable us to sequentially call a bunch of async functions. We can handle all errors in a single code block if we wish to do so. We can trigger multiple async calls and do further processing only when all of them have completed; or exit if any one of them throws an exception; or handle the first one that completes and ignore the rest. Promises enable us to retry async calls more easily.
-
What are some tools for working with promises? If your browser doesn't support promises, a polyfill will be needed. One option is to use promise-polyfill. Another polyfill is called es6-promise.
Bluebird is a JS library for promises. It can be used in Node.js and browsers. Using "promisification", it can convert old API into promise-aware API. Another useful library is Q. Alternatives include promise, lie, when and RSVP. A comparison of these promise libraries by size and speed is available.
Mocha, Chai and Sinon.JS are three suggested tools for testing asynchronous program flow. Mocha and Chai in combination work nicely for testing promises.
-
Can you give some tips for developers coding promises? Here are some tips, for beginners in particular:
- It's possible to write promise-based code in the manner of callback-style nested code. This is bad practice. Instead use a promise chain.
- Always handle errors using either
then(null, onRejected)
orcatch()
. - Avoid using the old-style
deferred
pattern that used to be common with jQuery and AngularJS. - Always return a value or throw an exception from inside
then
andcatch
methods. This is also handy for converting synchronous code into promisey code. Promise.resolve()
can wrap errors that occur in synchronous code. Be sure to use acatch
to handle all errors.- Note that
then(onFulfilled).catch(onRejected)
is different fromthen(onFulfilled, onRejected)
. The latter code will not catch exceptions that may occur insideonFulfilled
function.
-
I have a bunch of promises I wish to call sequentially. Can I use a for
loop?This is an interesting case where each promise invokes (presumably) some asynchronous code and yet we wish to wait for each asynchronous call to complete before we start the next promise. A promise executes as soon as it's created. If you have a bunch of promises to be called in sequence, any loop construct such as
forEach
will not work. Instead, use a chain of promises, that is, each promise is constructed within thethen
method of the previously fulfilled promise.
Milestones
1988
MIT researchers present a paper that defines and explains promises. They describe how promises can aid asynchronous programming in distributed systems, including sequences of async calls. It references an async communication mechanism called call-streams and illustrates the concepts in Argus programming language.
2009
2012
Promises/A+ specification version 1.0 is released. Versions 1.1 and 1.1.1 are subsequently released in 2013 and 2014 respectively. Promises/A+ is based on the earlier Promises/A but has some omissions, clarifications and additions. Specifically, progress handling and interactive promises are omitted. The focus has been to arrive at a minimal API for interoperability. For interoperability, the specification details the behaviour of the then
method of a promise object. The specification doesn't talk about how to create, fulfill or reject promises.
Sample Code
References
- AWS Docs. 2018. "Class Promise." AWS SDK for PHP 3.x API Documentation. Accessed 2018-02-12.
- Aderinokun, Ire. 2016. "JavaScript Promises 101." bitsofcode. July 12. Accessed 2018-02-12.
- Baker, Henry G. and Carl Hewitt. 1977. "The Incremental Garbage Collection of Processes." ACM Proceedings of the Symposium on Artificial Intelligence Programming Languages, pp. 55–59. Accessed 2018-02-12.
- Bluebird Docs. 2016a. "Promisification." API Reference. August 31. Accessed 2018-02-08.
- Bluebird Docs. 2016b. "API Reference." August 31. Accessed 2018-02-12.
- CommonJS Google Group. 2009. "Promise API Proposal." Google Groups. Accessed 2018-02-08.
- CommonJS Wiki. 2013. "Promises/A." January 24. Accessed 2018-02-08.
- Denicola, Domenic. 2012. "You're Missing the Point of Promises." Hidden Variables. October 14. Accessed 2018-02-08.
- ECMA International. 2015. "ECMAScript® 2015 Language Specification." 6th Edition. June. Accessed 2018-02-08.
- Foged, Poul. 2014. March 3. "JavaScript Promises – a comparison of libraries." Accessed 2018-02-12.
- Google GitHub. 2018. "Promises." GitHub. February 11. Accessed 2018-02-11.
- Hakes, Taylor. 2018. "promise-polyfill." GitHub. February 7. Accessed 2018-02-08.
- Lawson, Nolan. 2015. "We have a problem with promises." PouchDB. May 18. Accessed 2018-02-08.
- Lindesay, Forbes. 2018. "API Reference." February 2. Accessed 2018-02-08.
- Liskov, Barbara and Liuba Shrira. 1988. "Promises: Linguistic Support for Efficient Asynchronous Procedure Calls in Distributed Systems." ACM Proceedings of the SIGPLAN '88 Conferenece on Programming Language Design and Implementation, pp. 260-267. June 22-24. Accessed 2018-02-08.
- MDN Web Docs. 2018a. "Promise." January 21. Accessed 2018-02-08.
- MDN Web Docs. 2018b. "Using promises." January 21. Accessed 2018-02-08.
- Promises/A+. 2018a. Accessed 2018-02-08.
- Promises/A+. 2018b. "Promises/A+ Changelog." Accessed 2018-02-08.
- Promises/A+. 2018c. "Differences from Promises/A." Accessed 2018-02-08.
- Stittri, Mek. 2016. "Moving to fullstack end-to-end test automation with Node.js part 1 - Selenium Webdriver." Medium. January 3. Accessed 2018-02-08.
- Venkat R. 2017. "Tools for Promises Unit Testing." Tech.io. December 22. Accessed 2018-02-08.
Further Reading
- Rauschmayer, Alex. 2017. "Promises for asynchronous programming." Exploring ES6. Section 25. Accessed 2018-02-08.
- Arya, Naren. 2017. "Writing neat asynchronous Node JS code with Promises." DEV.BITS(). June 4. Accessed 2018-02-08.
- Denicola, Domenic. 2014. "The Revealing Constructor Pattern." Hidden Variables. February 14. Accessed 2018-02-08.
- Kundel, Dominik. 2016. "A quick guide to JavaScript Promises." Twilio Blog. October 3. Accessed 2018-02-08.