Bản chất Event Loop trong Node.js: Phân biệt process.nextTick(), setImmediate() và Promise
Câu hỏi kiểm tra bản chất lập trình bất đồng bộ Hãy dự đoán thứ tự in ra màn hình của đoạn mã sau: Nếu bạn không thể giải thích chính xác tại sao nextTick lại chạy trước Promise, hoặc khi nào setImme…
☰ Mục lục bài viết (5 phần) Mở / Đóng mục lục
Câu hỏi kiểm tra bản chất lập trình bất đồng bộ#
Hãy dự đoán thứ tự in ra màn hình của đoạn mã sau:
console.log('1 - Start');
setTimeout(() => console.log('2 - setTimeout'), 0);
setImmediate(() => console.log('3 - setImmediate'));
Promise.resolve().then(() => console.log('4 - Promise'));
process.nextTick(() => console.log('5 - nextTick'));
console.log('6 - End');
Nếu bạn không thể giải thích chính xác tại sao nextTick lại chạy trước Promise, hoặc khi nào setImmediate chạy trước setTimeout, bạn chưa thực sự làm chủ Event Loop của Node.js (dựa trên thư viện libuv).
Sơ đồ các pha (Phases) của Node.js Event Loop#
┌───────────────────────────┐
┌─>│ Timers │ (setTimeout, setInterval)
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ Pending Callbacks │ (I/O callbacks hệ thống)
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ Idle, Prepare │ (Dùng nội bộ)
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ Poll │ (Lấy sự kiện I/O mới)
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ Check │ (setImmediate callbacks)
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ Close Callbacks │ (socket.on('close'))
└───────────────────────────┘
Cơ chế Microtask Queue và process.nextTick()#
Bên cạnh các pha chính trên (Macrotasks), Node.js có 2 hàng đợi ưu tiên đặc biệt (Microtask Queues):
- nextTick Queue: Chứa các callback đăng ký qua
process.nextTick(). - Other Microtask Queue: Chứa các Promise resolve/reject callbacks.
Quy tắc: Bất cứ khi nào JavaScript call stack rỗng (sau khi chạy xong synchronous code hoặc giữa các pha của Event Loop), Node.js sẽ lập tức vét sạch toàn bộ hàng đợi nextTick, sau đó vét tiếp hàng đợi Promise trước khi chuyển sang pha tiếp theo!
Đáp án chính xác và Thứ tự thực thi#
1 - Start
6 - End
5 - nextTick (Ưu tiên số 1 trong microtasks)
4 - Promise (Ưu tiên số 2 trong microtasks)
2 - setTimeout (Pha Timers)
3 - setImmediate (Pha Check)
Góc thảo luận#
Tại sao việc lạm dụng process.nextTick() lồng nhau có thể làm "bỏ đói" (I/O starvation) toàn bộ hệ thống của bạn?
Xem thêm nội dung liên quan:
Thảo luận
1 phản hồi
Tham gia thảo luận
Bài liên quan trong #Backend & Microservices
-
Áp dụng Model Context Protocol (MCP) của Anthropic để kết nối AI với Postgres và Docker
Hoàng Nam (Tech Lead) · 💬 1 -
So sánh mô hình Embedding đa ngữ: OpenAI text-embedding-3 vs BGE-M3 vs Cohere
Minh Trí (AI Engineer) · 💬 1 -
Xây dựng Voice AI Agent thời gian thực với WebRTC và Whisper Live: Độ trễ dưới 500ms
Lan Anh (Senior Frontend) · 💬 1 -
Cấu hình Rate Limiting ở tầng Nginx và API Gateway: Chống DDOS Layer 7 hiệu quả
Đức Huy (DevOps Specialist) · 💬 1 -
Tokenization tiếng Việt của các LLM: Tại sao chi phí tiếng Việt đắt gấp 3 lần tiếng Anh?
Minh Trí (AI Engineer) · 💬 1