Một hàm được đổi sang async, nhưng test assert.throws không còn bắt được lỗi đầu vào. Trong thân hàm vẫn có throw và chưa đến bất kỳ await nào. Điểm cần nhìn là hợp đồng trả về đã đổi: lỗi không được bắt bên trong async function trở thành rejection của Promise mà lời gọi trả về.
Bài đối chiếu tài liệu ngày 09/11/2026 và chạy ví dụ bằng Node.js 24.18.1. Lưu các khối JavaScript dưới đây theo thứ tự vào file .mjs để dùng top-level await. Không gọi API, không sử dụng timer và không đo độ trễ của event loop.
Quan sát lỗi mà không tạo rejection bị bỏ quên
async function requirePositive(value) {
if (!Number.isInteger(value) || value <= 0) {
throw new RangeError('Expected a positive integer');
}
return value;
}
let caughtSynchronously = false;
let pending;
try {
pending = requirePositive(0);
} catch {
caughtSynchronously = true;
}
console.log(caughtSynchronously);
console.log(pending instanceof Promise);
console.log(await pending.then(
() => 'fulfilled',
error => error.name,
));
Kết quả là false, true và RangeError. Khối catch quanh lời gọi không nhận lỗi từ thân async function theo cách đồng bộ, nhưng Promise đã mang trạng thái lỗi. Ví dụ gắn hàm xử lý rejection ngay trong cùng lượt thực thi để quan sát nó; không cố ý để lỗi bị bỏ quên đến khi runtime báo unhandled rejection.
Async function trên MDN giải thích Promise được trả về và cách exception không được bắt trong thân hàm làm Promise bị reject. Điều này khác với nhận định sai rằng mọi dòng trong thân async đều bị trì hoãn sang một lúc khác: phần trước await đầu tiên vẫn có thể chạy ngay.
Await đưa rejection vào luồng try/catch đang chờ
Chạy tiếp trong cùng file:
try {
const value = await requirePositive(0);
console.log('accepted', value);
} catch (error) {
console.log('await caught', error.name);
}
await requirePositive(0).catch(error => {
console.log('promise catch', error.name);
});
console.log('valid', await requirePositive(3));
Ba dòng quan sát là await caught RangeError, promise catch RangeError và valid 3. Await nhận kết quả thành công hoặc làm lý do rejection xuất hiện như lỗi tại điểm đang chờ. Cách còn lại là xử lý bằng catch trên Promise.
Trong code sản phẩm, chọn chỗ xử lý theo trách nhiệm của tầng đang gọi. Nếu chỉ ghi log rồi bỏ qua, phía trên có thể hiểu thao tác đã hoàn tất thành công. Nếu cần chuyển lỗi thành một kết quả có trạng thái, định nghĩa cấu trúc ấy rõ ràng thay vì vô tình biến lỗi thành undefined.
Kiểm tra rejection bằng assertion đúng loại
import assert from 'node:assert/strict';
await assert.rejects(
() => requirePositive(0),
{name: 'RangeError', message: 'Expected a positive integer'},
);
assert.equal(await requirePositive(3), 3);
console.log('assertions passed');
Khối này đã đạt trên Node của bài. Node Assert mô tả assert.rejects cho trường hợp Promise bị từ chối. Không thay nó bằng assert.throws quanh lời gọi async chỉ vì bên trong hàm có từ khóa throw. Đồng thời, cần await assertion để quá trình kiểm tra chờ được kết quả lỗi mà nó đang xác nhận.
Giới hạn của câu nói “async trả Promise”
Kết luận trong bài áp dụng cho lỗi phát sinh trong thân async function khi hàm được gọi. JavaScript vẫn phải đánh giá biểu thức ở bên ngoài trước khi chuyển đối số vào hàm. Nếu một getter được dùng làm đối số tự ném lỗi ngay lúc truy cập, lỗi đó có thể nằm ngoài thân hàm và cần được phân tích riêng.
Tương tự, một hàm thông thường trả Promise không đồng nghĩa mọi validation trước khi return đều trở thành rejection. Khi review hoặc đổi API từ sync sang async, kiểm tra hợp đồng của chính hàm, không chỉ nhìn tên biến hoặc việc call site có dùng await.
Cách trả lời trong phỏng vấn
Hãy nêu ba điểm có thể kiểm chứng: lời gọi trả Promise, throw trong thân hàm dẫn đến rejection và caller cần await trong try/catch hoặc gắn handler tương ứng. Sau đó giải thích vì sao “chưa có await” không làm lời gọi quay lại hợp đồng ném lỗi đồng bộ của một hàm thường.
Thử thêm số âm, số thập phân và chuỗi '3'; chúng cần bị từ chối theo validation của ví dụ, còn số nguyên dương được resolve. Việc tách rõ lỗi đầu vào, cách truyền lỗi và chỗ xử lý giúp test mô tả đúng hành vi mà caller thực sự nhận được.


