Node.js › Error Handling

What is the try/catch/finally pattern's 'finally' block used for, and how does it behave with async/await?

Intermediate

Answer

The 'finally' block runs regardless of whether the try block succeeded or the catch block handled an error, making it the natural place for cleanup logic (closing a database connection, releasing a lock, stopping a loading spinner) that must happen in every case -- with async/await, a finally block correctly waits for the try/catch's async operations to settle before running, and importantly, an async operation inside finally itself is also properly awaited if the finally block itself is async.
async function processWithConnection(id) {
  const connection = await pool.connect();
  try {
    return await connection.query('SELECT ...', [id]);
  } catch (err) {
    logger.error(err);
    throw err;
  } finally {
    connection.release(); // always runs, whether the query succeeded or failed
  }
}
Real-world example A database query wrapper always releases its acquired connection back to the pool inside a finally block, guaranteeing the connection is returned regardless of whether the query succeeds, throws a validation error, or throws an unexpected database error.

Common follow-ups: What happens if the finally block itself throws an error -- does it override an error from the try or catch block?;Why is placing cleanup logic in finally more reliable than duplicating it at the end of both the try and catch blocks?