Bên cạnh xử lý lỗi, tạo ra lỗi bằng đối tượng Error cũng không kém phần quan trọng

Bên cạnh xử lý lỗi, tạo ra lỗi bằng đối tượng Error cũng không kém phần quan trọng

Tin ngắn hàng ngày dành cho bạn
  • Cũng giống như 12 Days of OpenAI - một chuỗi sự kiện diễn ra trong 12 ngày liên tiếp của OpenAI, mỗi ngày họ sẽ giới thiệu một công cụ "đột phá", và cứ như thế.

    DeepSeek đã bắt "trend" ngay sau đó với chuỗi 202502 Open-Source Week diễn ra ngay trong tuần sau. Mỗi ngày họ sẽ công bố một công cụ mã nguồn mở, trái được hoàn toàn với tính "Open" của AI. Chúng ta hãy chờ xem họ mang đến những dự án thú vị nào nhé 🤓. Chắc sẽ hấp dẫn lắm đây vì ai cũng biết từ lúc ra mô hình R1, Deepseek đã chiếm trọn tin tức nổi bật trên toàn thế giới.

    » Xem thêm
  • Grok 3 beta vừa ra mắt và cho mọi người dùng thử miễn phí có giới hạn số lần trong ngày (tài khoản trả phí hình như được dùng nhiều hơn). Trong đó có 2 tính năng nổi bật là Think và DeepSearch.

    Think thì chắc ai cũng biết hoặc dùng ở một số mô hình suy luận như ở ChatGPT rồi. Còn DeepSearch thì mới hơn, gõ điều bạn muốn vào thì nó sẽ tự lên mạng tìm kiếm thông tin rồi tổng hợp lại kết quả mà nó tìm thấy được. Khá hay nhưng chắc để tham khảo hoặc muốn tổng hợp thông tin nhanh chóng thôi chứ vẫn nên tự mình tìm kiếm thông tin 😅

    » Xem thêm
  • Có 2 phần mềm tiện ích cho Mac mà mỗi khi dùng máy Mac Mini hoặc Macbook có cắm thêm màn hình rời, thêm bàn phím với chuột nữa là BetterDisplayMac Mouse Fix. Đi qua từng cái nhé!

    BetterDisplay giúp tinh chỉnh kích thước của màn hình rời để đạt độ phân giải HiDPI. Như bạn biết Mac khá kén màn hình và tuỳ chọn độ phân giải trong cài đặt mặc định rất ít ỏi, nên BetterDisplay cung cấp nhiều lựa chọn phù hợp hơn.

    Cái thứ hai là Mac Mouse Fix, nếu dùng chuột ngoài bạn sẽ thấy nó cuộn không giống với Trackpad của Macbook cho lắm. Điều kì diệu xảy ra khi cài phần mềm này vào. Nó thêm hiệu ứng "smooth" và giúp cuộn chuột y như cuộn bằng Trackpad luôn. Thật thần kỳ.

    » Xem thêm

Vấn đề

Cách đây khá lâu tôi có một bài viết nói về Một số phương pháp xử lý lỗi (error handling) trong Node.js, nội dung trong bài xoay quanh việc làm thế nào để bắt được lỗi và xử lý chúng một cách dễ dàng. Trong bài viết này, tạm thời bỏ qua những phương pháp đó, chúng ta hãy đi sâu vào phân tích việc "đẩy" ra lỗi và làm sao để "bắt" được chúng.

Tôi cá là có nhiều người, trong đó có cả tôi từng đẩy ra một lỗi trông giống như thế này:

function login(username, password) {
  // code
  if (password != hash_password) {
    throw new Error("Password is incorrect");
  }
// code
}

Sau đó "bắt" lỗi:

try {
  login("admin", "123456");
} catch(e) {
  console.log(e.message);
  // logic handle
}

Chẳng có gì nhiều để bàn đến cách xử lý lỗi ở trên cả, khi "đẩy" ra một Error, nó sẽ mang theo rất nhiều thông tin hữu ích gây ra lỗi như vị trí (stack trace) và thông tin lỗi (message). Vì thế cho nên e ở trong catch(e) giúp ta dễ dàng truy ra được nguồn gốc lỗi để từ đó xử lý sao cho hợp lý.

Tôi từng gặp trường hợp đẩy ra một lỗi không đúng cách, thay vì new Error, lại đẩy ra một chuỗi hay một đối tượng. Giống như là:

throw 'Password is incorrect';

Với cách này, chúng ta vẫn có thể try catch. Tuy nhiên, e lúc này chỉ đơn giản là một chuỗi hoặc một đối tượng mà bạn đã đẩy ra trước đó, nó không chứa những thông tin quan trọng như stack trace và message như của Error. Chính vì thế, bất cứ khi nào đẩy ra một lỗi, hãy biến nó thành một instance của Error.

Error chỉ nhận vào tham số là một chuỗi, nó cũng chính là nội dung củae.message. Nếu ta cố tình truyền vào nhiều hơn một tham số hoặc tham số là một thứ gì đó khác string như object thì sẽ gây ra một hiện tượng giống như dưới đây:

throw new Error({ "name": "2coffee" });

VM400:1 Uncaught Error: [object Object]
    at <anonymous>:1:7

Sở dĩ tôi nêu ra vấn đề này vì có nhiều trường hợp, chúng ta cần thêm nhiều thông tin được vào trong một lỗi để tiện cho việc xử lý logic nào đó. Giả dụ như bên cạnh message, tôi cần thêm uuid là id của bản ghi gây ra lỗi, detail chứa một mô tả chi tiết hơn, code để chỉ định mã lỗi được định nghĩa trong hệ thống... thì với Error, hoàn toàn là không được.

Vậy có cách nào làm được điều này không?

Errors Class

Error là một đối tượng bị "đẩy" ra khi xảy ra lỗi trong thời gian chạy (runtime error). Error cũng có thể được sử dụng để làm đối tượng cơ sở cho các lỗi do người dùng xác định. Hay nói một cách dân dã là có thể tạo ra một Class kế thừa Error để tạo ra một đối tượng lỗi cho riêng mình.

JavaScript cung cấp một số đối tượng lỗi "tùy chỉnh" khác dựa trên Error mà có thể bạn đã từng gặp rất nhiều rồi như:

Để xem danh sách đầy đủ Error types, bạn đọc tham khảo tại Error types - Mozilla.

Điểm chung là chúng dựa trên Error nên mang đầy đủ thuộc tính quan trọng của Error. Ngoài ra, các lỗi này còn mang một sự minh bạch trong mã của bạn. Ví dụ khi đẩy ra một lỗi RangeError chúng ta có thể biết lỗi là do một giá trị nào đó nằm ngoài giá trị cho phép, thay vì throw new Error('The argument must be between 1 and 10') một cách chung chung.

Để phân biệt các đối tượng lỗi, chỉ cần thông qua các câu lệnh điều kiện như if...else, switch...case...

if (err instanceof RangeError) {
  // handle RangeError
} else if (err instanceof ReferenceError) {
  // handle TypeError
}
...

Các đối tượng lỗi tùy chỉnh này cũng tương tự như Error, chỉ khác mỗi name. Do đó nếu cần một lỗi "khác biệt" hơn, hãy chuyển sang phần tiếp theo.

Custom Errors Class

Chúng ta có thể tự xác định các loại lỗi của riêng mình bằng cách kế thừa từ Error. Sau đó, đẩy ra lỗi bằng cách throw MyError và sử dụng instanceof MyError để kiểm tra loại lỗi trong catch. Điều này dẫn đến các đoạn mã xử lý lỗi sạch sẽ và nhất quán hơn.

Cú pháp đơn giản nhất để tạo ra một MyError lỗi tùy chỉnh:

class MyError extends Error {
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
  }
}

MyError lúc này được gán name bằng constructor.name cũng chính là cái tên MyError của class. Tuy vậy, nó chưa có nhiều khác biệt gì so với Error thông thường, chỉ khác mỗi name. Chúng ta cần thêm một vài thuộc tính như code là mã lỗi và statusCode để định nghĩa cho HTTP response status codes.

class MyError extends Error {
  code;
  statusCode;

  constructor(message, code, statusCode) {
    super(message);
    this.name = this.constructor.name;
    this.code = code;
    this.statusCode = statusCode;
  }
}

Để đẩy ra lỗi, sử dụng cú pháp throw MyError:

try {
  throw new MyError("My error message", 123, 404);
} catch (err) {
  console.log(err.name, err.message, err.code, err.statusCode);
  // MyError My error message 123 404
}

Dựa vào tính năng này, có thể tạo ra nhiều lỗi riêng cho mình để phục vụ cho mục đích xử lý. Ví dụ, tạo ra class ApplicationError, DatabaseError, ValidateError... có các tính năng tương tương với lỗi hệ thống, lỗi cơ sở dữ liệu, lỗi xác thực dữ liệu... để từ đó ẩn hoặc hiện thông báo lỗi cho người dùng.

Tổng kết

Error là một đối tượng để xử lý lỗi trong chương trình viết bằng JavaScript. Cách tốt nhất để đẩy ra một lỗi là đẩy ra một Error thay vì chuỗi hoặc một đối tượng khác. JavaScript định nghĩa sẵn một vài "kiểu" lỗi dựa trên Error như ReferenceError, SyntaxError, RangeError... Ngoài ra, có thể tự tạo kiểu lỗi cho riêng mình bằng cách kế thừa từ Error.

Tài liệu tham khảo:

Cao cấp
Hello

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...