How to deal with long running operations
We have seen that long running processes can lock up an interface.
For example we may invoke a function that's supposed to retrieve data from a remote API. If the API is slow to return the data, we may be stuck in our application without being able to continue on our next task until all the data is received or an error is generated. This makes for a bad user experience.
One way to solve this problem is to use callback functions when we need to manage long running processes.
Another, more popular way, is to use Promises.
Promises
A Javascript Promise is an object that performs a long running, asynchronous operation and returns the result of this operation if it was successful, or an error if it wasn't.
Let's look at the code below. We defined a function called ~ that sets up and returns a Promise object.
The Promise object takes an arrow function which in turn takes two arguments, resolve
and reject
.
Inside the Promise we check if the isGood
parameter is true
.
If it is, and the promise succeeds, resolve
is called printing out a good message.
If isGood
is not true, the promise fails, reject
is called instead and the returned message is a bad one.
function makePromise(isGood) {
return new Promise((resolve, reject) => {
if (isGood) {
resolve('all good');
} else {
reject('all bad');
}
});
}
let p = makePromise(true);
console.log(p); // all good
When we invoke makePromise()
, we pass a true
object. This resolves the promise and the string 'all good'
is returned.
If the value passed to makePromise()
was false
, the promise would not be resolved and the 'all bad'
message would be printed out.
Promises can be in a pending state if the Promise is neither resolved nor rejected.
Pending promises
In the following code, we create a new Promise and we pass an empty anonymous function as an argument to it. Since this empty function has not called either resolve
or reject
, the Promise is now in a pending state.
We can see it's pending when we print it out on the console.
console.log(new Promise(() => {}));
// Promise { <pending> }
If the promise is not resolved yet, it sits there in a pending state. In the real world that could happen if you are making an external API call and the call takes a while to resolve.
How to get values out of a Promise
We get values out of a promise with .then()
and .catch()
.
We attach these methods at the end of the Promise.
If the promise is resolved, the result will be available inside .then()
. Otherwise, the result will be available on the .catch()
method.
We simply concatenate these two methods one after the other and this lets us take care of both outputs. Here's an example:
p = makePromise(true);
console.log(p); // Promise { 'all good' }
p = makePromise(false);
console.log(p); // Promise { <rejected> 'all bad' }
p
.then(goodValue => console.log(goodValue)) // all good
.catch(badValue => console.log(badValue)) // all bad
When we write Promises it's helpful to separate .then()
and .catch()
on different lines for better readability.
If the result of the first .then()
needs to be processed further we can also concatenate multiple .then()
methods. The result of the first .then()
will then be passed to the next .then()
method.
We will see more Promises when we talk about retrieving data from external APIs in React.
I write daily about web development. If you like this article, feel free to share it with your friends and colleagues.
You can receive articles like this in your inbox by subscribing to my newsletter.
Top comments (2)
Why is there in the title "React", this article is about Promises in Javascript maybe, not in React in particular. The code above will work in Node or any other JS library...
You are right, this is not specific to React. I modified the title. Thanks for the feedback.