Event loop





Node.js is a single-threaded application, but it can support concurrency via the concept of event and callbacks. Every API of Node.js is asynchronous and being single-threaded, they use async function calls to maintain concurrency. Node uses observer pattern. Node thread keeps an event loop and whenever a task gets completed, it fires the corresponding event which signals the event-listener function to execute.

Event-Driven Programming

Node.js uses events heavily and it is also one of the reasons why Node.js is pretty fast compared to other similar technologies. As soon as Node starts its server, it simply initiates its variables, declares functions and then simply waits for the event to occur.

In an event-driven application, there is generally a main loop that listens for events, and then triggers a callback function when one of those events is detected.

Event Loop

Although events look quite similar to callbacks, the difference lies in the fact that callback functions are called when an asynchronous function returns its result, whereas event handling works on the observer pattern. The functions that listen to events act as Observers. Whenever an event gets fired, its listener function starts executing. Node.js has multiple in-built events available through events module and EventEmitter class which are used to bind events and event-listeners as follows −

// Import events module
var events = require('events');

// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();

Following is the syntax to bind an event handler with an event −

// Bind event and event  handler as follows
eventEmitter.on('eventName', eventHandler);

We can fire an event programmatically as follows −

// Fire an event 
eventEmitter.emit('eventName');

Example

Create a js file named main.js with the following code −

// Import events module
var events = require('events');


// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();

// Create an event handler as follows
var connectHandler = function connected() {
   console.log('connection succesful.');
  
   // Fire the data_received event 
   eventEmitter.emit('data_received');
}

// Bind the connection event with the handler
eventEmitter.on('connection', connectHandler);
 
// Bind the data_received event with the anonymous function
eventEmitter.on('data_received', function(){
   console.log('data received succesfully.');
});

// Fire the connection event 
eventEmitter.emit('connection');

console.log("Program Ended.");

Now let's try to run the above program and check its output −

$ node main.js

IT should produce the following result −

connection successful.
data received successfully.
Program Ended.

How Node Applications Work?

In Node Application, any async function accepts a callback as the last parameter and a callback function accepts an error as the first parameter. Let's revisit the previous example again. Create a text file named input.txt with the following content.

Tutorials Point is giving self learning content
to teach the world in simple and easy way!!!!!

Create a js file named main.js having the following code −

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {
   if (err){
      console.log(err.stack);
      return;
   }
   console.log(data.toString());
});
console.log("Program Ended");

Here fs.readFile() is a async function whose purpose is to read a file. If an error occurs during the read operation, then the err object will contain the corresponding error, else data will contain the contents of the file. readFilepasses err and data to the callback function after the read operation is complete, which finally prints the content.

Program Ended
Tutorials Point is giving self learning content
to teach the world in simple and easy way!!!!!

Nguồn: https://www.tutorialspoint.com/nodejs/nodejs_event_loop.htm

-----------

Event Loop trong Javascript

Một trong khái niệm khá trừu tượng và khó hiểu trong Javascript là Event Loop (vòng lặp xử lý sự kiện). Có nhiều người có thể đã lập trình Javascript trong nhiều năm nhưng không thật sự hiểu chính xác Event loop trong Javascript làm gì. Vì vậy, trong bài viết này tôi hy vọng sẽ làm sáng tỏ hơn về Event loop trong Javascript, giúp các bạn cảm thấy nó không còn phức tạp nữa.
 

Javascript trong browser

Khi nói về Javascript, chúng ta thường nghĩ về nó trong ngữ cảnh một trình duyệt, bởi vì hầu hết chúng ta thường viết Javascript cho phía client. Tuy nhiên, để chạy một ứng dụng web bất kỳ đều cần rât nhiều công nghệ, ví dụ như Javascript Engine (như trong Chrome V8), một tập hợp các Web API (như DOM), Event Loop, Event Queue, ...
 
Có rất nhiều thứ chúng ta cần tìm hiểu, nhưng trong phạm vi bài viết này chúng ta sẽ cùng tìm hiểu về Javascript Engine và Event Loop.
 

Javascript Engine

Có một vài sự khác biệt trong các phiên bản của Javascript Engine nhưng phiên bản phổ biến nhất là Google Chrome V8 Engine (không chỉ hoạt động trên trình duyệt mà còn hoạt động trên server thông qua NodeJS). Nhưng chính xác thì Javascript Engine làm được những gì? Vâng, thực ra rất đơn giản, công việc của nó là chạy xuyên suốt các dòng lệnh Javascript trong một ứng dụng và xử lý chúng cùng một lúc. Đúng vậy, cùng một thời điểm, có nghĩa là Javascript là một single-thread (đơn luồng). Do đó, nếu bạn đang chạy một dòng code trong Javascript mà cần một thời gian dài để trả về kết quả, nó sẽ block (chặn) tất cả các đoạn code sau nó. Và chúng ta không muốn điều đó xảy ra, đặc biệt là trên trình duyệt. Hãy thử tưởng tượng rằng bạn đang ở một trang web và bấm vào một nút trên trang web, sau đó trang web bị treo. Bạn sẽ thử bấm vào các nút khác nhưng không được, các nút khác không hoạt động. Nguyên nhân của việc này (giả sử không có lỗi) là do các nút bấm sau đó kích hoạt các đoạn Javascript nhưng đã bị chặn. 
 
Vậy Javascript xử lý một dòng lệnh tại cùng một thời điểm như thế nào? Nó sử dụng một Call stack.
Bạn có thể hình dung về Call stack giống như một chồng đĩa xếp từ thấp lên cao, chiếc đĩa xếp cuối cùng ở đỉnh chồng đĩa, nó sẽ được lấy ra sớm nhất và chiếc đĩa ở ngay dưới nó sẽ là chiếc tiếp theo... Mỗi lệnh được nạp vào Call stack theo trình tự xếp đĩa, còn trả về giống như lấy dần đĩa từ trên đỉnh
 
Hãy cùng xem một ví dụ:
/* Trong file main.js */

var firstFunction = function () {  
  console.log("I'm first!");
};

var secondFunction = function () {  
  firstFunction();
  console.log("I'm second!");
};

secondFunction();

/* Kết quả:
 * => I'm first!
 * => I'm second!
 */
Và đây là chuỗi kết quả sẽ xảy ra với Call stack:
  • Chạy file main.js

       Học lập trình trực tuyến

  • Gọi function secondFunction()

     Học lập trình trực tuyến cơ bản

  • Gọi secondFunction() sẽ làm firstFunciton() được gọi

     Học lập trình trực tuyến nâng cao

  • Chạy firstFunction() sẽ làm chuỗi "I'm first!" được log ra trước, sau đó do không còn dòng code nào trong firstFunction()nữa nên nó sẽ bị xóa khỏi Call stack

     Học lập trình trực tuyến kiếm việc

  • secondFunction() tiếp tục chạy và log ra chuỗi "I'm second!", sau đó do không còn dòng code nào nữa nên secondFunction() cũng bị xóa khỏi Call stack

     Học lập trình trực tuyến khởi nghiệp

  • Cuối cùng không còn dòng code nào trong main.js nữa nên nó cũng bị xóa khỏi Call stack

       Học lập trình trực tuyến xin việc làm

Vậy còn Event Loop thì sao?

Giờ chúng ta đã biết Call stack trong Javascript hoạt động như nào, hãy quay trở lại vấn đề blocking code. Chúng ta đã biết là nên tránh blocking, nhưng làm thế nào để tránh? Rất may cho chúng ta, Javascript cung cấp một cơ chế bất đồng bộ thông qua các hàm callback. Các hàm callback cũng giống như các hàm khác mà bạn dùng trong Javascript nhưng nó sẽ không được thực thi ngay mà phải đợi đến thời điểm khác. Nếu bạn đã từng sử dụng hàm setTimeout trong Javascript thì bạn đã quen thuộc với các hàm callback! Hãy cùng xem một ví dụ:
/* Trong file main.js */

var firstFunction = function () {  
 console.log("I'm first!");
};

var secondFunction = function () {  
 setTimeout(firstFunction, 5000);
 console.log("I'm second!");
};

secondFunction();

/* Kết quả:
 * => I'm second!
 * (Và sau 5 giây)
 * => I'm first!
 */

Và sau đây là thứ tự hoạt động trong Call stack

  • Sau khi secondFunction() được đặt vào Call stack, hàm setTimeout() được gọi và cũng được đặt vào Call stack
   Học lập trình trực tuyến đổi nghề
  • Ngay sau khi hàm setTimeout() thực thi, browser đặt hàm callback của nó (trong trường hợp này là hàm firstFunction) vào trong một Event table (bảng sự kiện). Hãy nghĩ Event table như một quầy đăng ký: call stack sẽ đăng ký với Event table một hàm nào đó sẽ chỉ được thực thi khi có một sự kiện cụ thể nào đó xảy ra. Và khi sự kiện đó xảy ra, Event table sẽ di chuyển hàm đã đăng ký sang Event queue (hàng đợi). Event queue chỉ đơn giản là một địa điểm cho các hàm chờ được gọi và di chuyển sang Call stack.

    Bạn cũng có thể hỏi: "Vậy chính xác thì khi nào các hàm trong Event queue di chuyển sang Call stack?". Vâng, Javascript tuân theo một quy luật rất đơn giản: Có một process liên tục kiểm tra xem có Call stack nào rỗng không, và nếu rỗng thì nó sẽ kiểm tra Event queue có hàm nào đang đợi hay không. Nếu có thì hàm đầu tiên trong Event queue sẽ được gọi và di chuyển sang Call stack. Nếu Event queue rỗng thì process này vẫn tiếp tục chạy vô thời hạn. Và những cái mà tôi vừa miêu tả chính là Event loop!

  • Quay trở lại với ví dụ trên, thực thi hàm setTimeout() sẽ di chuyển hàm callback của nó (trong trường hợp này là firstFunction) vào Event table và đăng ký nó với một thời gian delay là 5 giây
   Học lập trình trực tuyến khởi nghiệp
 
  • Chú ý rằng, một khi hàm callback được di chuyển đến Event table, không có bất kì đoạn code nào bị block. Browser sẽ không chờ 5 giây trước khi thực hiện tác vụ khác, mà thay vào đó nó sẽ thực thi dòng lệnh tiếp theo trong secondFunction() là log ra chuỗi "I'm second!"
   Học lập trình trực tuyến chất lượng nhất
 
  • Tại thời điểm này secondFunction() và main.js đã thực thi xong
   Học lập trình trực tuyến hiệu quả nhất
 
  • 5 giây sau đó, Event table sẽ di chuyển hàm firstFunction() sang Event queue
   Học lập trình trực tuyến cơ bản đến nâng cao
 
  • Event loop liên tục kiểm tra Call stack và hiện tại nó phát hiện call stack đang rỗng nên gọi firstFunciton và tạo ra một Call stack mới
   Học lập trình trực tuyến cấp tốc
  • Một khi firstFunction được thực thi xong, chúng ta trở lại trạng thái Call stack rỗng, Event table không còn hàm nào để lắng nghe và Event queue cũng rỗng
   Học lập trình trực tuyến cho người mới bắt đầu
 
Nguồn: https://techmaster.vn/posts/33416/hoc-lap-trinh-web-javascript