Ai mà chẳng có lỗi lầm cơ chứ, Javascript cũng vậy :D. Xử lý lỗi là điều mà bạn sẽ gặp thường xuyên trong Javascript, nhất là các bác code NodeJs. Và xử lý nó là cả một nghệ thuật đấy, cùng mình tìm hiểu nào.

Quăng tao cái lỗi

Cách cơ bản nhất là như thế này, tạo một Error Object từ hàm Error và throw nó

throw new Error("Lỗi rồi")

Cách này sẽ hoạt động với mọi trình duyệt. Để tạo một Error Object thì ta chỉ cần truyền string vào constructor. Nhưng thỉnh thoảng mình thấy một số người lại throw lỗi như thế này.

throw "Lỗi rồi"

Cái này không sai, bạn có thể throw bất cứ thứ gì bạn muốn từ ObjectBooleanString,…

throw { name: "Nicholas" }
throw true
throw 12345
throw new Date()

Nhưng điều này không phải là Best Practice, vì nếu ta throw một kiểu không phải là Error Object thì ta sẽ mất đi thông tin lỗi, và thường các thông tin này là những thông tin giá trị như tên file bị lỗi, vị trí lỗi… Đây đều là những thứ giúp cho việc debug dễ dàng hơn, nhất là dự án với số lượng code lớn. Test trên Chrome thử nhé

Nghệ thuật xử lý lỗi trong Javascript

Throw một Error Object cho ra chi tiết hơn hẳn

Thuộc tính stack

Lợi ích của Error Object là nó tự động lưu lại nơi nó được tạo ra. Cơ chế này có ở cả các Javascript Engine như V8 hay trên trình duyệt

// error.js
var err = new Error()
console.log(typeof err.stack)
console.log(err.stack)

và sẽ log ra terminal như thế này

// Terminal
string
Error
    at Object.<anonymous> (/private/tmp/error.js:2:11)
    at Module._compile (module.js:411:26)
    at Object..js (module.js:417:10)
    at Module.load (module.js:343:31)
    at Function._load (module.js:302:12)
    at Array.0 (module.js:430:10)
    at EventEmitter._tickCallback (node.js:126:26)

Như bạn thấy đó, ngay cả khi mình không dùng throw thì V8 engine vẫn nói cho chúng ta biết nơi object được tạo ra và làm thế nào mà nó ở đó.

Có rất nhiều biến thể của Error Object

Bên cạnh hàm Error (hàm cơ bản nhất), còn có 7 hàm khác để bạn có thể tường minh hơn khi làm việc với lỗi trong JavaScript.

  • EvalError: Tạo một instance đại diện cho một lỗi xảy ra liên quan đến hàm toàn cục eval().
  • InternalError: Tạo một instance đại diện cho một lỗi xảy ra khi một lỗi bên trong JavaScript Engine được ném. Ví dụ: “quá nhiều đệ quy”.
  • RangeError: Tạo một instance đại diện cho một lỗi xảy ra khi một biến số hoặc tham số nằm ngoài phạm vi hợp lệ của nó.
  • ReferenceError: Tạo một instance đại diện cho một lỗi xảy ra khi hủy tham chiếu của một tham chiếu không hợp lệ.
  • SyntaxError: Tạo một instance đại diện cho một lỗi xảy ra trong khi phân tích cú pháp mã trong eval().
  • TypeError: Tạo một instance đại diện cho một lỗi xảy ra khi một biến hoặc một tham số có kiểu không hợp lệ.
  • URIError: Tạo một instance đại diện cho một lỗi xảy ra khi encodeURI() hoặc decodeURI() truyền các tham số không hợp lệ.

Vậy bạn sẽ tự hỏi Nếu như ta muốn truyền một object vào Error Object thì sao, thì đây là câu trả lời. Bạn có thể tạo một class CustomError riêng và thừa kế Error

class CustomError extends Error {
  constructor(message, student) {
    super(message)
    this.student = student
    this.name = "CustomError"
  }
}

try {
  throw new CustomError("Endgame", { name: "Thanos" })
} catch (err) {
  alert(err.message) // Endgame
  alert(err.student.name) // Thanos
  alert(err instanceof Error) // true
  alert(err instanceof CustomError) // true
}

Tổng kết

Nếu bạn đang throw một string hay một object nào đó không phải từ các Error object thì hãy đổi lại ngay hôm nay đi! Error Object nó sinh ra để làm điều này cơ mà. Hi vọng bài viết của mình giúp ích được các bạn :D, hẹn gặp lại ở bài sau nhé~~

Tham khảo: