Event-driven architecture là mô hình mà luồng điều khiển do sự kiện quyết định thay vì chạy tuần tự từ trên xuống. Trong Node.js, bạn đăng ký hàm xử lý cho một sự kiện và runtime sẽ gọi hàm đó khi sự kiện xảy ra, thay vì block để chờ.
Hãy hình dung như quầy lễ tân: nhân viên không đứng chờ một khách làm xong thủ tục mới tiếp người tiếp theo. Nhân viên ghi nhận yêu cầu, chuyển cho bộ phận phía sau xử lý và tiếp khách khác. Khi xong việc, chuông báo reo và nhân viên quay lại hoàn tất.
Cơ chế này dựa trên event loop và I/O không block. Hầu hết đối tượng như http.Server, fs.ReadStream, Socket đều kế thừa EventEmitter và cho phép on() để lắng nghe. Khi bạn gọi thao tác I/O như đọc file hay query DB, Node.js uỷ thác việc chờ cho hệ thống qua libuv và tiếp tục chạy code khác. Khi hệ điều hành báo I/O hoàn tất, event được đưa vào hàng đợi và callback chạy trên main thread duy nhất. Nhờ vậy một thread có thể phục vụ nhiều kết nối đồng thời vì thời gian chờ I/O không chiếm CPU.
Lỗi thường gặp là block event loop. Vòng lặp for nặng, JSON.parse với payload lớn hay crypto.pbkdf2Sync chạy đồng bộ sẽ giữ main thread và khiến mọi request, timer khác phải xếp hàng. Lỗi khác là quên gỡ listener bằng removeListener() hoặc dùng on() thay vì once() khi chỉ cần chạy một lần, dẫn tới rò rỉ bộ nhớ. Nếu không lắng nghe sự kiện 'error' trên EventEmitter, lỗi có thể làm crash process.
Lưu ý: Event-driven giúp Node.js xử lý tốt workload I/O-bound với nhiều kết nối đồng thời, nhưng không làm code chạy song song trên nhiều core. Với tác vụ CPU-intensive, hãy chuyển sang worker_threads, child process hoặc tách thành service riêng thay vì chạy trên event loop.