Javascript exception and error handling

This tutorial is a part of the Learn everything about Javascript in one course.

Exception is represented by "Error" object

Exceptions are events that occur during the execution of programs that disrupt the normal flow of instructions. For example: using not available variable, syntax error, ... You will see them very often in your daily work.

exception.js
// Exception example
// this error this thrown by the system
console.log(a) // ReferenceError: a is not defined

Error is an global object that represent an exception. You can crash the program intentionally by "throwing" an error. Syntax: throw new Error('error message'). If you look at the console, the error message has all the information related to it.

error.js
// Intentional error/exception thrown by user
throw new Error('this exception is intentional') // Error: this exception is intentional
$ node error.js
/learn-javascript/lecture-22/error.js:2
throw new Error('this exception is intentional') // Error: this exception is intentional
^

Error: this exception is intentional
    at Object.<anonymous> (/Users/sesv/learn-javascript/lecture-22/error.js:2:7)
    at Module._compile (internal/modules/cjs/loader.js:959:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10)
    at Module.load (internal/modules/cjs/loader.js:815:32)
    at Function.Module._load (internal/modules/cjs/loader.js:727:14)
    at Function.Module.runMain (internal/modules/cjs/loader.js:1047:10)
    at internal/main/run_main_module.js:17:11

The term exception and error are usually used interchangeably in Javascript. It's important to handle error correctly as it will crash your program and it will not response to user anymore.

Use "try...catch" to catch error and handle it

Any error thrown in the try block will be catch and passed to catch(error) block. In this catch(error) block, we can handle the error and response accordingly. The program won't crash anymore if we can catch the error.

try_catch.js
// Use "try...catch" to catch error and handle it
try {
  throw new Error('this exception is intentional') // Error: this exception is intentional
} catch(err) {
  console.log('now we can do error handling logic here') // now we can do error handling logic here
  console.log(err) // Error: this exception is intentional
}
console.log('program continue to run without crashing')
// program continue to run without crashing

Use ".catch(error)" to catch error from a promise and handle it

try...catch will not be able to catch an error from Promise because when a Promise returns a value, the program has already "moved on".

try_catch_promise_will_not_work.js
// try...catch will not be able to catch an error from Promise
try {
  new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('error from promise')
    }, 1000)
  })
} catch(err) {
  console.log(err) // nothing
}
$ node try_catch_promise.js
(node:55982) UnhandledPromiseRejectionWarning: error from promise
(node:55982) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)

We use chained .catch(error) to catch and handle error for a promise. Syntax: promise.then(...).catch(err => { // handle error here })

chained_catch_promise_error.js
// chained ".catch(error)" to catch and handle error for a promise

new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('error from promise')
  }, 1000)
}).then().catch(err => {
  console.log('handle promise error here')
  console.log(err)
})
console.log('program continue to run without crashing')
// program continue to run without crashing
// handle promise error here, 1 second later
// error from promise

Use "try...catch" to catch and handle "async/await" error

async/await syntax makes catching and handling error for asynchronous operation easy and intuitive like synchronous code. This is why async/await syntax is encouraged to be used as much as possible.

switch_case.js
// Use "try...catch" to catch and handle "async/await" error

const login = () => new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(`can't login`) // we emulate and error will be thrown
  }, 1000); // after 1 second
})

const getUser = async () => {
  try {
    const user = await login() // async/await syntax makes it easy to read code
  } catch(err) { // we catch the error here
    console.log('handle error logic goes here')
    console.log(err)
  }
}

getUser()
console.log('program continue to run without crashing')
// program continue to run without crashing
// handle error logic goes here
// can't login

Summary

  1. Error will always occur and it will crash your program.
  2. Catching and handling error is an important part of writing a program.
  3. There's two way to catch and handle error: try...catch and chained .catch(err).