Câu hỏi & gợi ý trả lời
Q1. Event Loop trong Node.js hoạt động như thế nào?
Event Loop là cơ chế cho phép Node.js thực thi các thao tác I/O bất đồng bộ mà không cần chặn luồng chính (Main Thread). Nó liên tục kiểm tra các hàng đợi (Timers, Pending Callbacks, Poll, Check) để thực thi các callback tương ứng khi tác vụ hoàn thành.
Q2. Sự khác biệt giữa process.nextTick() và setImmediate()?
process.nextTick() ưu tiên thực thi ngay sau khi operation hiện tại hoàn thành, trước khi vào phase tiếp theo của Event Loop. Ngược lại, setImmediate() được thực thi trong phase Check của Event Loop (sau phase Poll).
Q3. Tại sao Node.js được coi là single-threaded nhưng vẫn xử lý được lượng request lớn?
Node.js dùng kiến trúc event-driven và non-blocking I/O. Các tác vụ nặng (File I/O, Network) được libuv offload xuống OS hoặc thread pool. Kết quả được trả về qua callback mà không chặn luồng chính thực thi code JS.
Q4. Cluster module trong Node.js dùng để làm gì?
Cluster cho phép tạo ra các worker processes chạy trên nhiều CPU core khác nhau. Điều này giúp tận dụng sức mạnh đa nhân của server, tăng khả năng chịu tải và tính sẵn sàng của ứng dụng.
Q5. Buffer trong Node.js là gì?
Buffer là vùng nhớ ngoài V8 heap, dùng để lưu trữ dữ liệu nhị phân (binary data) thuần túy. Nó rất quan trọng khi làm việc với streams, đọc/ghi file hoặc các thao tác mạng (TCP) mà không cần chuyển đổi sang String.
Q6. Sự khác biệt giữa CommonJS và ES Modules (ESM)?
CommonJS (require/module.exports) là chuẩn cũ, chạy đồng bộ (synchronous). ESM (import/export) là chuẩn mới của ECMAScript, hỗ trợ load bất đồng bộ và tối ưu hóa code thông qua phân tích tĩnh (static analysis).
Q7. Streams trong Node.js là gì và tại sao nên sử dụng?
Streams cho phép đọc hoặc ghi dữ liệu từng phần (chunks) thay vì load toàn bộ file vào RAM. Điều này giúp tối ưu hóa bộ nhớ đáng kể khi xử lý các tệp tin lớn hoặc dữ liệu từ network.
Q8. Middleware trong Express.js là gì?
Middleware là các function có quyền truy cập vào request object (req), response object (res) và hàm next(). Chúng dùng để thực hiện các tác vụ trung gian như logging, authentication, hoặc validation trước khi đi đến xử lý logic chính.
Q9. EventEmitter trong Node.js hoạt động thế nào?
Đây là triển khai của Observer Pattern. Các object kế thừa từ EventEmitter có thể 'emit' ra sự kiện, và các phần khác của ứng dụng có thể 'on' (lắng nghe) để thực thi callback tương ứng khi sự kiện xảy ra.
Q10. Cách xử lý lỗi (error handling) trong async/await là gì?
Nên sử dụng try-catch block bao quanh các hàm async. Với Express, cần dùng global error-handling middleware để bắt tất cả các lỗi xảy ra trong quá trình xử lý request, tránh làm crash server.
Q11. Sự khác biệt giữa Promise và Callback?
Promise là object đại diện cho kết quả tương lai, giúp code dễ đọc, chainable và xử lý lỗi tập trung qua .catch(). Callback là cơ chế cũ, dễ gây ra 'Callback Hell' khi lồng nhiều hàm vào nhau.
Q12. Memory leak trong Node.js thường do đâu?
Thường do biến toàn cục (global variables), các closure không được giải phóng, hoặc event listeners không được gỡ bỏ (removeListener). Có thể dùng heapdump hoặc Chrome DevTools để kiểm tra và debug.
Q13. Tại sao JWT (JSON Web Token) được ưa chuộng trong Node.js?
JWT là giải pháp xác thực stateless. Server không cần lưu session vào DB mà chỉ cần verify chữ ký (signature) của token. Điều này giúp hệ thống dễ dàng scaling (horizontal scaling) hơn.
Q14. Race Condition trong Node.js là gì?
Xảy ra khi nhiều thao tác bất đồng bộ cùng truy cập và thay đổi một tài nguyên tại cùng một thời điểm. Cần xử lý bằng cách dùng locking cơ chế database transaction hoặc queuing để đảm bảo tính nhất quán dữ liệu.
Q15. Khi nào nên dùng Worker Threads?
Nên dùng khi ứng dụng cần xử lý các tác vụ nặng về CPU (CPU-intensive) như tính toán math phức tạp, nén file, xử lý hình ảnh. Nó giúp thực hiện tính toán trên luồng riêng, không làm lag Event Loop.