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.
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,
thenmethod 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
catchstatements. 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
thenmethod) while the async call is still in progress.
Callbacks can be specified via the
thenmethod. Two things are possible when the
thenmethod 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.
Promises also simplify the handling of exceptions. Anytime an exception is thrown it can be handled by a single
catchmethod. In fact, the
catchmethod is a simplification of
thenmethod for exception handling.
What are the states and rules of transition of a promise object?
- 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?
Among the non-standard methods are
Promise.prototype.nodeify. GuzzleHttp's Promise implementation in PHP provides methods
cancel. Bluebird adds useful methods such as
Could you share some details of the
onRejectedare both optional
onFulfilledis a function, it's called once when
onRejectedis a function, it's called once when
qis resolved with value
xif either function
qis rejected with reason
eif either function
onRejectedthrows an exception
onFulfilledis not a function,
qwill be fulfilled with the value of
onRejectedis not a function,
qwill be rejected with the reason of
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?
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.
Can you give some tips for developers coding promises?
- 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
- Avoid using the old-style
deferredpattern that used to be common with jQuery and AngularJS.
- Always return a value or throw an exception from inside
catchmethods. 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 a
catchto handle all errors.
- Note that
then(onFulfilled).catch(onRejected)is different from
then(onFulfilled, onRejected). The latter code will not catch exceptions that may occur inside
I have a bunch of promises I wish to call sequentially. Can I use a
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
forEachwill not work. Instead, use a chain of promises, that is, each promise is constructed within the
thenmethod of the previously fulfilled promise.
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.
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.
- AWS Docs. 2018. "Class Promise." AWS SDK for PHP 3.x API Documentation. 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.
- 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.
- 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.