Chapter 4 · Real programs

Exceptions

You are reading the whole lesson on one page. Back to one step at a time

Step 1 of 22 · Concept

Fail well

By the end of this lesson your programs fail well. They say what went wrong, and carry on where they can. You will:

  • refuse with an error, and catch it,
  • make your own kind of error,
  • survive bad input and missing files.
import { Account } from "./account.js";

const account = new Account("Ada");
account.deposit(5);
console.log("Asking for 10");
account.withdraw(10);
console.log("Balance:", account.balance);
import { Account } from "./account.js";

const account = new Account("Ada");
account.deposit(5);
try {
  account.withdraw(10);
  console.log("after withdraw");
} catch (e) {
  console.log(e.message);
}
console.log("done");
import { Account } from "./account.js";

const account = new Account("Ada");
account.deposit(8);
for (const amount of [3, 10, 3]) {
  account.withdraw(amount);
}
console.log(`Balance: ${account.balance}`);
class InsufficientFunds extends Error {
  constructor(message) {
    super(message);
  }
}
throw new InsufficientFunds("balance is 5, asked for 10");
class InsufficientFunds extends Error {
  constructor(message) {
    super(message);
    this.name = "InsufficientFunds";
  }
}
const accounts = new Map();
const account = accounts.get("Bo");
try {
  account.withdraw(10);
} catch (e) {
  if (e instanceof InsufficientFunds) {
    console.log("Refused:", e.message);
  } else {
    throw e;
  }
}
// 1. class TooYoung extends Error, with its name
function checkAge(age) {
  // 2. under 13: throw a TooYoung
  console.log(`Welcome, ${age}`);
}
for (const age of [15, 11]) {
  checkAge(age);
  // 3. catch a TooYoung: log its name and message
}
import { readFileSync } from "node:fs";

try {
  JSON.parse("abc");
} catch (e) {
  console.log(e.name);
  console.log(e.message);
}
try {
  readFileSync("data.txt", "utf8");
} catch (e) {
  console.log(e.code);
}
console.log(Number.isNaN(Number("abc")));
function load(text) {
  try {
    console.log("parsing");
    return JSON.parse(text);
  } catch (e) {
    console.log("caught:", e.name);
    return null;
  } finally {
    console.log("finally");
  }
}
console.log(load("[1]"));
console.log(load("abc"));
import { readFileSync } from "node:fs";

const lines = readFileSync(0, "utf8").trim().split("\n");
for (const line of lines) {
  // 1. parse the line in a try
  // 2. a number, or throw volume must be a number
  // 3. log Volume: ..., or Settings refused: ...
}
class InsufficientFunds extends Error {
  constructor(message) {
    super(message);
    this.name = "InsufficientFunds";
  }
}
function withdraw(balance, amount) {
  if (amount > balance) {
    throw new InsufficientFunds(
      `balance is ${balance}, asked for ${amount}`
    );
  }
  return balance - amount;
}
try {
  withdraw(5, 10);
} catch (e) {
  if (e instanceof InsufficientFunds) {
    console.log(`Missing: ${e.missing}`);
  } else {
    throw e;
  }
}
Terminal
Step 1 of 10An uncaught error ends the program

Keyboard shortcuts

The step

ContinueEnter
Previous / next stepAlt+[ · Alt+]
Move along the steps bar← → Home End, then Enter
From a quiz's title to its answers↓
Skip to the stepTab, then Enter (first on the page)
Course outlineAlt+O
These shortcuts?

The workspace

Run the stepCtrl+Enter (⌘↵ on a Mac)
Lesson → editor → consoleF6 (Shift+F6 back)
Output ↔ TerminalCtrl+`
Focus the editorCtrl+. (⌘. on a Mac)
Hide or show the lessonAlt+L
Restore, close a messageEsc (outside the editor and the terminal)

The editor

Leave the editorF6 (Shift+F6 back); or Ctrl+M (⌃⇧M on a Mac), then Tab moves the focus (not in the vim mode)
Open a file by nameCtrl+P (⌘P on a Mac)
All commandsCtrl+Shift+P (⌘⇧P on a Mac) or F1
Go to a lineCtrl+G (⌃G on a Mac)
Show or hide the filesCtrl+B (⌘B on a Mac)
Previous / next file tabCtrl+Shift+[ · Ctrl+Shift+] (⌘⇧[ · ⌘⇧] on a Mac)
The file tabs← → Home End on a tab; Delete closes it
Save the files nowCtrl+S (⌘S on a Mac)
Go to a symbol in the fileCtrl+Shift+O (⌘⇧O on a Mac)
Go to the definitionF12
Format the fileCtrl+Shift+F (⌘⇧F on a Mac), or Shift+Alt+F
Go back / forward after a jumpAlt+← · Alt+→ (⌃- · ⌃⇧- on a Mac)