01/10/2018, 16:07
Vấn đề throw sau lệnh sử dụng await, chương trình vẫn chạy tiếp
Cho đoạn code như sau:
async function main() {
acb(); await waitNextCycle(); console.log(2);
}
function waitNextCycle() {
return Promise.resolve();
}
async function acb() {
await waitNextCycle(); console.log(1); throw new Error(5);
}
process.on('uncaughtException', function (err) {
console.log('error'); console.error(err); process.exit(-1);
});
process.on('unhandledRejection', (err) => {
console.log('reject'); console.error(err); process.exit(-2);
});
main();
Khi chạy đến throw new Error(5);
mình kì vọng nó sẽ ngay lập tức nhảy vào event unhandledRejection
và tắt chương trình.
Nhưng không, chương trình vẫn chạy tiếp từ chỗ console.log(2);
, sau khi chạy hết hàm main
, rồi chạy đến hết file, event unhandledRejection
mới được chạy??
Vậy có cách nào để mình throw một phát là dừng chương trình luôn được không? (Mình không muốn để process.exit ngay chỗ throw đâu)
Bài liên quan
Hàm main phải gọi await abc() chứ nhỉ
Chương trình của mình không thể await ở acb được, thật sự trong app của mình thì acb nó là một lệnh require.
Hiện tại thì cách lý giải duy nhất mình đoán được là một lần await thì nodejs đẩy một event vào event loop, những event do await tạo ra có độ ưu tiên rất cao, còn unhandledRejection thì lại là một event có độ ưu tiên thấp :’(
Ngọc thử async trc, await sau
Tham khảo: https://kipalog.com/posts/JS--async-await-don-gian
Mục 3.4
nếu làm thế thì app mình chạy lộn xộn mất, chỗ acb đó trong app mình là một lệnh require, mình không để await chỗ đó là có chủ ý, thật sự là mình rành xài async await lâu rồi.
File đưọc require chứa khoảng vài trăm lệnh gọi hàm đều y như hàm acb, và trong file đó, trăm lệnh call đều không nằm trong function nào khác. File được require thì mình muốn nó đơn giản không lồng hàm.
Lý do có hàng trăm lệnh: mình đang vận dụng generative programming.
Theo mình đoán Promise chỉ là JavaScript thuần thôi, bằng chứng ban đầu nó làdefer
của jQuery, rồi AngularJS gọi nó làq
. Sau này JavaScript mới cho Promise thành standard api của NodeCòn pendingTask trong Event Loop, mình nghĩ, là hàm
console.log
, gọi tắt là log.“log” thực chất là async function gọi đến libuv để in argument của log ra stdout, thuộc task của hệ điều hành (OS task)
Có 3 loại task được thực hiện trong event loop, thứ tự từ trên xuống dưới:
Sau khi đi kiểm tra lại source code, khi gọi
resolve()
hayreject()
trên Promise, 1 trong 2 function này đều phải gọi ít nhất 1 lầnsetTimeout(function () { }, 0)
, màsetTimeout()
tạo 1 timer task trong event loop.async function main() {
acb(); // 1
await waitNextCycle(); // 2
console.log(2); // 3
}
giải pháp là dùng Promise.all
cho lệnh 1 và 2 vô list Promise.all
khi đó độ ưu tiên như nhau, ai chạy ra lội thì vô catch của promise, trong catch throw thêm cái nữa là dc nhỉ
Thôi mọi người không cần giúp nữa, mình viết lại code luôn rồi, cách làm ban đầu của mình không phù hợp với async await của JS engine. Lý do là Unhandled Rejection event có độ ưu tiên rất thấp so với các event khác, thấp hơn cả event của setTimeout.