Todays topic is Promises. I’ve been working with python as my first programming language and only the synchronous part. Thus, promises and asynchronous programming takes some effort to get my head around.
Basically, a Promise object is used to request some resource and continue running lines of code, while the request is returning a response. This could be requesting a website, asking if a specific product is in stock or if it will rain in a few minutes or not.
When the Promise object is first initialized, it is in the state of pending. A pending Promise will always settle in one of two states: Either it resolves or it rejects. Resolving a Promise means a successful response to a request. Rejecting is obviously the opposite.
Important to remember is, that a Promise can resolve and still return an invalid response. That is, the Promise can only check whether the request was resolved or not. If the requested resource returned invalid data or you requested something the server could not return, it still may return some kind of data for you to read.
When initializing a new Promise object, you have to pass it an Executor function. The executor function takes 2 parameters – a resolve and reject parameter. The Executor function holds the logic of how and when to resolve or reject the promise’ request for something.
const executorFn = (resolve, reject) => {if (condition) { resolve(‘success!’) } else { reject(‘failure!’) } }
Also, when initializing a new Promise object it can be stored into a variable pointing to the promise object. This could look like this:
const promise = new Promise(executorFn);
After this, you have to assign some code telling the program how to handle the resolved or rejected response. This is done by “chaining” .then() methods to the promise. When adding a .then() method, you feed it “handlers”. Handler functions handle the returned value from a settled promise. As a promise can either resolve or reject, we also need a succes-handler and rejection-handler. There are 2 ways of doing this. Either you give .then both handlers, beginning with the succes-handler, then as a 2nd parameter add the failure-handler. Another way of doing this, and a more clear way of expressing how the promise should react to success and failure is chaining a .catch() method after the .then() method. Doing this, you feed .then() the succes-handler and .catch() the failure-handler. This could look like this:
const promise = new Promise(executorFn);
promise.then(succes-handler).catch(failure-handler);
In some cases, you have multiple promises chained together. In other words, when the resolved promise itself returns a promise, that in turn has to resolve or reject in order to settle the entire promise chain. When working with multiple promises, your code could look like this:
const promise = new Promise(executorFn);
promise.then(return new Promise(executorFn)).then(succes-handler-for-second-promise).catch(failure-handler-for-any-of-the-promises)
As promises always will be settled, chaining promises presents a potentially tricky bug to catch. For instance, if the logic second .then() is buggy – i.e. if you forget to return the promise object – the second .then() will be invoked on a promise settled with the values as the original promise. This last part, I’m not really sure how to reproduce, or what it exactly means, so this will be a subject of study for another time [link to future blogpost].
As this is at the core of building responsive webapps that doesn’t block the user from interacting when data is loading, I will return to the subject later and meanwhile build into some of my own projects.
How do you use promises, and how do you learn topics, that is rather different from what you’ve worked with earlier?