Events trong NodeJS
Trong bài tiếp theo của seri học lập trình NodeJS căn bản chúng ta sẽ đi tìm hiểu về khái niệm event loop (luồng sự kiện) và event trong NodeJS.
Trong các ứng dụng NodeJS, các khái niệm về callback và event được thực hiện đồng thời. Bởi trong ứng dụng NodeJS được xử lý đơn luồng và hầu hết các API mà nó cung cấp đều là các tác vụ bất đồng bộ. Những khái niệm về Event-Driven, Non-blocking I/O, Event Loop,... giúp js tận dụng được hết sức mạnh của phần cứng và nhiều lợi ích khác trong lập trình.
I. Một số khái niệm cơ bản cần biết
Trước khi phân tích và tìm hiểu về event loop trong NodeJS, chúng ta sẽ tìm hiểu một vài khái niệm mà mình sẽ sử dụng phần tiếp theo như JavaScript Engine, Heap, Stack,..
1. Javascript Engine
Javascript Engine là chương trình hoặc tình thông dịch mã javascript, nếu như các bạn đã đọc các bài viết trước thì cũng thấy mình nhắc đến việc NodeJS xây dựng dựa trên Javascript engine là Chorme V8 phát triển bởi Chromium Project. Một Javascript Engine có thể biên dịch như bình thường hoặc biên dịch just-in-time từ Javascript thành bytecode.
Bài viết này được đăng tại [free tuts .net]
Ngoài V8, chúng ta còn có rất nhiều các Javascript Engine khác như :
- SpiderMonkey : cũng đang được sử dụng trên trình duyệt Firefox, Gnone Shell
- JavaScriptCore : được sử dụng trên trình duyệt Safari
- Chakra : được sử dụng trên trình duyệt Internet Explorer
- Hermes: được Facebook sử dụng cho các app Android được viết bằng ReactNative
Engine gồm 2 phần chính đó là Heap và Stack, mình sẽ giới thiệu bên dưới.
2. Heap Mermory
Như cái tên của nó Heap Mermory là vùng nhớ để chứa kết quả tạm thực thi các hàm trong stack, heap được cấp phát bộ nhớ càng cao thì chương trình chạy càng nhanh.
3. Stack
Không giống như các ngôn ngữ lập trình khác như PHP, Ruby,.. Javascript là một ngôn ngữ lập trình đơn luồng (single thread), nghĩa là nó chỉ có thể thực hiện 1 công việc trong 1 thời điểm nhất định.
Stack là một cấu trúc dữ liệu, nó có nhiệm vụ ghi nhớ vị trí của các lệnh trong quá trình chạy. Vì Javascript là một ngôn ngữ đơn luồng nên nó chỉ có 1 stack. Chúng ta thử lấy 1 ví trị để hiểu hơn về stack nhé, mình sẽ sử dụng các hàm đệ quy như sau:
function boo() { bar() } function bar() { return foo() } function foo() { return 'foo' } boo()
Khi chạy đoạn Javascript trên, stack sẽ ghi nhớ lần lượt các lệnh như hình minh họa bên dưới :
Các lệnh sẽ được đưa vào stack lần lượt là main(), boo(), bar(), và cuối cùng là foo(), vì foo() return về một giá trị nên chương trình sẽ kết thúc. Stack sẽ loại bỏ lần lượt các câu lệnh trong nó và hoàn thành xong nhiệm vụ của mình.
Ngoài ra về stack còn có các vấn đề mà bạn cần biết như :
- StackOverFollow : khi mà gọi một hàm đệ quy lặp đi lặp lại không kết thúc sẽ gây ra hiện tượng tràn stack.
- Stacktrade : Thứ tự, đường đi của các câu lệnh chứa trong stack. Như trong vị dụ trên thì quá trình đi từ hàm main() đến hàm foo() được gọi là một stacktrade.
II. Event Loop là gì? Nó hoạt động như thế nào?
Sau khi tìm hiểu về các khái niệm cơ bản ở phần trên, chúng ta sẽ đi tìm hiểu về event loop là gì và cách hoạt động của nó. Để hiểu rõ về cách hoạt động của event loop thì bạn phải đọc các khái niệm ở phần trên và về bài về Callback trong NodeJS trước nhé ! Phần này sẽ dùng rất nhiều kiến thức từ các bài trước đó.
1. Khái niệm về Event Loop trong NodeJS
Hiểu đơn giản event loop là một vòng lặp vô tận có nhiệm vụ lắng nghe các event. Nhiệm vụ của nó rất đơn giản là đọc các stack và event queue rồi đưa vào lại stack, theo mình hiểu đó là như vậy. Đến đây các bạn cũng chưa hình dung nó hoạt động như nào vì vậy cùng xem ví dụ cụ thể ở phần tiếp theo nhé.
2. Event Loop hoạt động như thế nào ?
Chúng ta sẽ sử dụng đoạn code sau và xem hình ảnh để quan sát cách mà event loop hoạt động như thế nào nhé ?
console.log('Hello guys !') setTimeout(cb => { console.log('NodeJS') }, 5000) console.log('Bye !')
Cách thức hoạt động của event loop sẽ như hình:
Trước tiên chương trình sẽ đưa lần lượt các hàm theo thứ tự vào stack :
- console.log('Hello guys')
- setTimeout()
- console.log('Bye!')
Khi đưa hàm setTimeout vào stack, đồng thời nó cũng đưa cho Web APIs một Timer, sau 5s Timers sẽ trả lại một callback function cho Web APIs. Khi WebAPIs nhận được callback nó sẽ truyền lại vào Queue. Event Loop bây giờ sẽ xuất hiện và sẽ kiểm tra xem trong Queue và Stack có tồn tại bất cứ element nào không? Nếu trong Stack không có bất cứ element nào và trong Queue có element thì event loop sẽ đẩy element trong Queue vào trong Stack.
III. Tìm hiểu về Events trong NodeJS
Để hiểu được phần này chúng ta cần phải đọc về khái niệm event loop trước nha !
1. Events là gì?
Trong một sự án NodeJS, events và callback là 2 khái niệm được sử dụng đồng thời với nhau. Vì một ứng dụng viết bằng Nodejs chỉ xử lý đơn luồng bởi thế nó sử dụng hàm async để duy trì đồng thời các hoạt động của nó. Node quan sát event loop và sau khi nó được hoàn thành, nó sẽ gọi sự kiện tương ứng để cho các hàm được thực thi.
Khi Node được khởi tạo trên server, đầu tiên nó sẽ khởi tạo các biến, các hàm cần thiết và đợi event xảy ra. Nó là lý do tại sao mà Nodejs có thể nhanh hơn các công nghệ khác rất nhiều. Nodejs tạo ra một vòng lặp chính để lắng nghe các sự kiện và sau đó nhận lại callback function khi mà sự kiện đó được xác định.
2. Thao tác với Event
Chúng ta có thể thao tác với các sự kiện trong Nodejs bằng cách require module event và khởi tạo một đối tượng mới là EventEmitter():
//Require module events const event = require('events'); //Khởi tạo đối tượng eventEmitter const eventEmitter = new event.EventEmitter();
Để thêm sự kiện mới chúng ta sử dụng hàm phương thức on :
// Bind event and even handler as follows eventEmitter.on(eventName, eventHandler);
ở đây chúng ta có 2 tham số cần truyền vào
- eventName: tên sự kiện
- eventHandler: hàm xử lý khi eventName được gọi
Sau khi thêm sự kiện bạn cần phải thực thi nó bằng phương thức:
// Fire an event eventEmitter.emit('eventName');
3. Ví dụ về event
Tạo một file có tên là event.js
và sử dụng đoạn code sau :
// Import events module const events = require('events'); // Tạo một đối tượng EventEmitter mới const eventEmitter = new events.EventEmitter(); // Tạo hàm để nhận sự kiện const connectHandler = function connected() { console.log('Kết nối sự kiện connection.'); // Thực thi sự kiện có tên data_received eventEmitter.emit('data_received'); } // Thêm sự kiện connection và khai báo hàm nhận sự kiện eventEmitter.on('connection', connectHandler); // Thêm sự kiện data_received và khai báo hàm nhận sự kiện eventEmitter.on('data_received', function(){ console.log('Kết nối sự kiện data_received.'); }); // Thực thi sự kiện có tên connection eventEmitter.emit('connection');
Mở terminal và chạy dòng lệnh:
node event
Chúng ta sẽ nhận được kết quả như sau :
Kết nối sự kiện connection. Kết nối sự kiện data_received.
Trên đây là những kiến thức cơ bản về Event trong Nodejs. event và callback là phần rất quan trọng và sử dụng rất nhiều. Mong bài viết này có thể giúp ích cho bạn cho việc lập trình với Nodejs, cảm ơn bạn đã quan tâm bài viết này.