Bài 10. Xử lý lỗi và gỡ lỗi

Lỗi là chuyện bình thường khi lập trình. Bài này dạy phân loại lỗi, try/catch/finally, tự định nghĩa lỗi, xử lý lỗi bất đồng bộ và dùng DevTools để gỡ lỗi hiệu quả.

40 phútCơ bản
Bạn sẽ học được
  • Phân biệt lỗi cú pháp, lỗi chạy, lỗi logic
  • Dùng try/catch/finally và throw
  • Tạo lớp lỗi riêng, dùng cause
  • Gỡ lỗi bằng breakpoint trong DevTools
Thuật ngữ cần biết
Exception
Lỗi được ném ra khi chạy và có thể bắt.
Stack trace
Danh sách lời gọi hàm dẫn tới lỗi.
Breakpoint
Điểm dừng chương trình để kiểm tra.
Unhandled rejection
Promise bị lỗi mà không ai bắt.

Khái niệm và lý thuyết

Có ba loại lỗi: cú pháp (SyntaxError, chương trình không chạy), lỗi chạy (TypeError, ReferenceError, RangeError...) và lỗi logic (chạy được nhưng sai kết quả, khó phát hiện nhất). Lỗi chạy là đối tượng Error có name, message, stack.

Nguyên tắc: bắt lỗi ở nơi có thể xử lý (hiển thị thông báo, thử lại, dùng giá trị mặc định); nếu không xử lý được thì để lỗi lan lên, đừng “nuốt” lỗi trong catch rỗng.

try, catch, finally

function docCauHinh(chuoi) {
  try {
    return JSON.parse(chuoi);
  } catch (err) {
    console.error("JSON hỏng:", err.message);
    return {};
  } finally {
    console.log("Đã đọc cấu hình"); // luôn chạy
  }
}

Lỗi tự định nghĩa

class LoiHopLe extends Error {
  constructor(truong, message, options) {
    super(message, options);
    this.name = "LoiHopLe";
    this.truong = truong;
  }
}
function kiemTraTuoi(t) {
  if (!Number.isInteger(t)) throw new LoiHopLe("tuoi", "Tuổi phải là số nguyên");
}
try { kiemTraTuoi("abc"); }
catch (e) {
  if (e instanceof LoiHopLe) alert(`${e.truong}: ${e.message}`);
  else throw e;                      // lỗi khác: ném tiếp
}
// Gói lỗi gốc: throw new Error("Không tải được", { cause: err });

Lỗi bất đồng bộ

async function tai(url) {
  try {
    const res = await fetch(url);
    if (!res.ok) throw new Error("HTTP " + res.status); // fetch không tự ném khi 404
    return await res.json();
  } catch (err) {
    console.error(err);
    throw err;
  }
}
window.addEventListener("unhandledrejection", e => console.warn("Chưa bắt:", e.reason));

Gỡ lỗi với DevTools

  • Mở F12 → Sources, bấm số dòng để đặt breakpoint, hoặc chèn lệnh debugger;.
  • Dùng F10 (bước qua), F11 (bước vào), xem biến ở khung Scope và Watch.
  • console.table(mang), console.time()/timeEnd() giúp xem dữ liệu và đo thời gian.
  • Trong VS Code, chạy “JavaScript Debug Terminal” để gỡ lỗi Node.js.
Mẹo hay

Đọc stack trace từ trên xuống: dòng đầu tiên thuộc mã của bạn thường là nơi cần xem.

Lưu ý

catch {} rỗng che giấu lỗi, khiến lỗi xuất hiện ở chỗ khác khó tìm hơn nhiều.

Thực hành
  1. Viết hàm chia hai số, ném RangeError khi chia cho 0, bắt và hiển thị.
  2. Tạo lớp LoiHopLe, dùng kiểm tra form đăng ký.
  3. Gọi một URL sai bằng fetch, xử lý cả lỗi mạng và mã 404.
  4. Đặt breakpoint trong vòng lặp tính tổng, quan sát biến thay đổi.
Tóm tắt bài học
  • Ba loại lỗi: cú pháp, chạy, logic.
  • try/catch/finally; throw đối tượng Error.
  • Lỗi tùy chỉnh + cause giúp phân loại và truy vết.
  • DevTools với breakpoint là công cụ gỡ lỗi chính.