The promise pattern in javascript is a mighty abstraction. Apart from the obvious advantage of writing sequential asynchronous code in less error-prone synchronous manner; it provides inherient error handling. Bluebird's promise library provides potpourri of features including filtered exception catching.
Let's look at a simple promise chain:
checkNetworkConnection()
.then(checkToken)
.then(checkSerialPort)
.catch(function(error){
log.error(error.message);
});
This is a very neat looking promise chain, however if any of then functions reject or throw exception, the tailing catch is not going know where that happened, unless a switch case is used to check possible error type/code. Bluebird's promise provides a clean mechanism for implementing filtered catch. The catch syntax for filtering looks like this:
.catch(
class ErrorClass|function(any error)|Object predicate...,
function(any error) handler
) -> Promise
The first argument is a filter clause which identifies type of error the catch method will handle, this filter clause can be an error class/constructor. Let's define a custom error object:
// ErrorA.js
function ErrorA(message) {
this.name = "Error A";
this.code = "ERROR_CODE_A";
this.message = message;
}
ErrorA.prototype = Object.create(Error.prototype);
module.exports = ErrorA;
Same thing in ES6:
// NetworkConnectionError.js
export default class NetworkConnectionError extends Error{
constructor(){
super("Error A");
this.code = "ERROR_CODE_A";
}
}
// index.js
import NetworkConnectionError from './NetworkConnectionError';
function checkNetworkConnection(){
return new Promise(function(resolve, reject){
reject(new NetworkConnectionError())
});
}
checkNetworkConnection()
.then(checkServer)
.then(checkSerialPort)
.catch(NetworkConnectionError.check(), function(error){
log.error(error.message);
})
.catch(function(error){
log.error(error.message);
});