Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at JavaScript promise mistakes we should avoid.
Chaining and Errors
We can have one or more then
calls in a chain.
If we have multiple then
calls that don’t have error handlers, then the error is passed on until there’s an error handler.
So if we have:
asyncFunc1()
.then(asyncFunc2)
.then(asyncFunc3)
.catch(function(reason) {
// ...
});
Then catch
will be called if any of the promises in the chain has an error.
Common Mistakes
A promise chain can be built with a chain of then
calls.
One way we can make a mistake is that we return the original promise instead of the promise that’s returned from then
.
For example, we shouldn’t write:
function foo() {
const promise = promiseFunc();
promise.then(result => {
//....
});
return promise;
}
Instead, we should write:
function foo() {
const promise = promiseFunc();
return promise.then(result => {
//...
});
}
We got to return the promise chain instead of the original promise.
Nesting Promises
We should never nest promises. The whole point of using promises is to avoid nesting.
For example, if we have something like:
promiseFunc1()
.then(result1 => {
promiseFunc2()
.then(result2 => {
//...
});
});
We should rewrite it to:
promiseFunc1()
.then(result1 => {
return promiseFunc2();
})
.then(result2 => {
//...
});
Creating Promises Instead of Chaining
We shouldn’t create promises instead of chaining.
So instead of creating promises the Promise
constructor:
function insert(entry) {
return new Promise((resolve, reject) => {
db.insert(entry)
.then(resultCode => {
//...
resolve(resultCode);
}).catch(err => {
reject(err);
})
});
}
We just return the promise chain:
function insert(entry) {
return db.insert(entry)
.then(resultCode => {
//...
}).catch(err => {
handleError(err);
})
}
What we shouldn’t do is create a new promise by using the Promise
constructor.
then
already returns a promise, so we don’t need the Promise
constructor.
Using then()
for Error Handling
then
shouldn’t be used for handing.
catch(callback)
is short for then(null, callback)
.
However, using in the same line is problematic.
The error callback in the then
method doesn’t catch errors that occur in the rejection by the fulfillment callback.
For instance, if we have:
promiseFunc1()
.then(
value => {
fooo();
return promiseFunc2();
},
error => {
//...
});
If an error occurs in the first then
callback, the 2nd one won’t catch it.
Error Handling
There’re 2 kinds of errors that can occur.
Operational errors happen when a correct program encounters an exceptional situation.
For example, if someone enters something in an invalid format, then that’s an operational error.
A programmer error is an incorrect behavior in our program.
For instance, we may be passing in an array to a function when it actually expects a string, then that’s a programmer error.
To handle operational errors, we should either throw exceptions or invoke rejections.
If it’s a programmer error, then the program should fail quickly.
We can throw an exception to make it clear that the program failed.
Conclusion
There’re many common mistakes that we should avoid with promises.