While Neil's answer is pretty accurate, things may change in the future with the advent of async functions in ECMAScript 8. Support for async functions was added in Node 7.6 and Node 8 (LTS). In addition, Node 8 added the util.promisify
function which opens up much potential.
Throwing an error inside an async function is the equivalent of rejecting a promise. Instead of having multiple different ways of handling errors (catch
for synchronous functions, (err, ...args)
for callbacks, and .catch()
for promises), asynchronous code will look synchronous and the try/catch construct can be used.
For example:
Using promises, handling async errors with .catch
and sync errors with try/catch:
const promisify = require('util').promisify
const fs = require('fs')
const readFileAsync = promisify(fs.readFile)
readFileAsync('foo.txt', {encoding: 'utf8'})
.then(data => {
console.log('CONTENT:', data)
try {
let moreOtherStuff = syncThing(data)
return Promise.resolve(otherSyncThing(moreOtherStuff))
} catch (err) {
return Promise.reject(err)
}
})
.catch(err => console.error(err))
Using async functions, handling errors with try/catch:
const promisify = require('util').promisify
const fs = require('fs')
const readFileAsync = promisify(fs.readFile)
(async () => {
try {
let data = await readFileAsync('foo.txt', {encoding: 'utf8'})
console.log('CONTENT:', data)
let moreOtherStuff = syncThing(data)
return otherSyncThing(moreOtherStuff)
} catch (err) {
console.error(err)
throw new Error(err)
}
})()
As you can see, the code uses the same try/catch block to handle the error (whether or not this is desirable depends on the use case and personal preference). Regardless, the code looks more synchronous when read top-down.
In addition to all of this, try/catch/finally statements could not be optimized prior to V8 5.3 (the JavaScript engine used in Node 7.x) so performance could be a factor. However this should no longer be the case going forward, as the engine is now supposedly able to optimize those blocks.