Khối xử lý lỗi lại gây thêm lỗi khi đọc message. JavaScript cho phép ném nhiều loại giá trị, nên tên biến error không bảo đảm đó là một đối tượng Error. Ở ranh giới với dependency hoặc mã cũ, hãy xử lý giá trị bắt được như một đầu vào chưa rõ kiểu.
1. throw chuỗi không tạo Error tự động
try {
throw 'dependency failed';
} catch (value) {
console.log(typeof value); // string
console.log(value.message === undefined); // true
console.log(value); // dependency failed
}
Giá trị bắt được là chính chuỗi đã ném, không phải Error được tự tạo. Quy tắc throw được mô tả trong MDN throw. Ví dụ chỉ tái hiện hành vi ngôn ngữ; với mã do mình kiểm soát, nên ném Error để có thông tin chẩn đoán nhất quán.
Đọc value.message trong ví dụ không cho thông báo gốc. Nếu một logger chỉ ghi trường đó, sự kiện thất bại có thể xuất hiện mà không còn nội dung hữu ích. Kiểm thử đường lỗi nên quan sát cả giá trị đưa vào logger thay vì chỉ xác nhận catch đã được chạy.
2. Destructuring trong catch có thể thất bại trước phần thân
try {
try {
throw null;
} catch ({ message }) {
console.log('inner handler reached');
}
} catch (error) {
console.log(error instanceof TypeError); // true
}
Đối tượng null không thể dùng cho object destructuring, nên phần thân catch bên trong chưa được chạy. Catch bên ngoài nhận TypeError mới từ bước gán biến bắt lỗi. Xem phần catch binding trong MDN try...catch.
Thêm giá trị mặc định cho thuộc tính message không giải quyết được đầu vào null. Nếu không có contract chắc chắn, bắt bằng một biến đơn trước rồi phân loại bên trong thân catch. Cách này cũng giúp test trực tiếp null, undefined, số và các object tùy biến.
3. Chuẩn hóa ở ranh giới mà vẫn giữ giá trị gốc
function normalizeCaught(value) {
if (value instanceof Error) return value;
return new Error('A non-Error value was thrown', { cause: value });
}
const original = new TypeError('invalid input');
console.log(normalizeCaught(original) === original); // true
const wrapped = normalizeCaught(null);
console.log(wrapped.message); // A non-Error value was thrown
console.log(wrapped.cause === null); // true
Helper trả lại Error cùng realm, giữ nguyên tham chiếu, loại lỗi và stack đã có. Với giá trị khác, nó tạo một Error có thông báo cố định và lưu nguyên nhân trong cause. cause có thể là giá trị bất kỳ; xem MDN Error.cause. Runtime cần hỗ trợ tùy chọn cause để dùng ví dụ như viết ở đây.
Helper không tự đọc message trên object lạ và không ép nó thành chuỗi. Một object có getter hoặc phương thức chuyển đổi tự định nghĩa có thể chạy mã khi được đọc hay chuyển đổi; việc chuẩn hóa ở đây chỉ lưu tham chiếu gốc, chưa phải bộ serialize dữ liệu tổng quát.
instanceof Error trong helper là chính sách đơn giản cho cùng realm. Một Error đến từ iframe hoặc VM khác có thể bị bọc lại. Nếu ứng dụng thực sự trao đổi lỗi qua những ranh giới này, hãy định nghĩa contract và kiểm tra riêng thay vì xem helper như bộ nhận diện Error toàn cục.
4. Chọn thông báo giao diện riêng với dữ liệu chẩn đoán
Chuẩn hóa giúp tầng xử lý có hình dạng Error nhất quán, nhưng không tự quyết định nên hiển thị gì cho người dùng. Thông báo công khai nên mô tả thao tác thất bại; logger nội bộ có thể giữ thông tin nguyên nhân theo chính sách của hệ thống.
Trong test, dùng các giá trị như null, undefined, 0, false và chuỗi rỗng. Không dùng điều kiện if (value) để kết luận có lỗi hay không: những giá trị falsy đó vẫn có thể được throw. Nếu tầng hiện tại không bổ sung ngữ cảnh hoặc chính sách mới, ném lại chính giá trị nhận được có thể là lựa chọn đúng.
- Bắt giá trị chưa rõ kiểu bằng một biến đơn.
- Chỉ truy cập thuộc tính sau khi đã có contract phù hợp.
- Giữ nguyên Error khi không cần thay đổi ngữ cảnh.
- Giữ giá trị gốc khi cần bọc lỗi.
- Test cả đầu vào falsy và object có hành vi tùy biến.
Sáu khối mã Việt–Anh đã chạy bằng Node.js, kèm kiểm tra bảo toàn tham chiếu, nguyên nhân falsy và object có getter message ném lỗi. Chưa tích hợp logger thực tế hay kiểm thử qua iframe.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.