Như ta đã biết JavaScript là một ngôn ngữ single-thread nhưng có khả năng hỗ trợ concurrency thông qua các khái niệm event và callback. Những API của JavaScript là bất đồng bộ và single-threaded, và nó sử dụng những lời gọi hàm bất đồng bộ để duy trì concurrency. JavaScript sử dụng Observer pattern, nó sẽ luôn quan sát 1 vòng lặp sự kiện - Event loop và khi bất cứ task nào được thực hiện xong, nó sẽ kích hoạt 1 event tương ứng báo hiệu cho các hàm lăng nghe sự kiện - event listener thực thi. Và hôm nay chúng ta sẽ tìm hiểu xem Event loop là gì thông qua bài viết này.
Bài viết gồm 3 mục chính:
Event loop hoạt động như một hàng đợi queue bên trong một vòng lặp liên tục while-true, mỗi khi hàng đợi có ít nhất 1 event (eventLoop.length > 0) thì event đó sẽ được lấy ra khỏi hàng đợi và được thực hiện. Event này chính là hàm callback hay chính là thằng CB ở ví dụ trên.
Vùng nhớ Stack: Là vùng nhớ làm nên tính single-threaded của JS, đây chính là nơi các function đc thực thi
Browser và WebAPI: được tích hợp sẵn có trong trình duyệt, có khả năng lấy dữ liệu từ trình duyệt và môi trường xung quanh để sử dụng
Callback queue: Hàng đợi chứa các callback (cách mà event loop hoạt động)
Sau khi đã nắm được các khái niệm, chúng ta sẽ đi tìm hiểu xem event loop vận hành thực tế với các câu lệnh như thế nào?
Bước 1: Push main() vào trong Stack, bắt đầu thực hiện bên trong hàm main().
Bài viết gồm 3 mục chính:
- Event loop là gì?
- Các khái niệm xung quanh event loop
- How event loop work?
1. Event loop là gì?
Như ta đã biết, JavaScript là single-threaded, tuy nhiên nó vẫn có khả năng xử lý các tác vụ IO non-blocking là nhờ có vòng lặp sự kiên - Event loop. Để dễ hiểu hơn ta sẽ lấy một ví dụ về gọi AJAX như sau:
Giả sử A là một chương trình JS, gọi 1 AJAX request đến server là đợi kết quả về. Kết quả sẽ đc một hàm callback xử lý gọi là CB. Và môi trường chứa trương chính JS đang chạy là H (Host)
Khi tạo 1 request AJAX, A sẽ nói với H rằng: "Ê, giờ tao tạm dừng thực hiện để lấy dữ liệu từ server về. Khi nào dữ liệu về tới mày kêu thằng CB xử lý zùm tao nha!". Thằng H sẽ sau đó sẽ chờ response chứa dữ liệu về, sau đó khi dữ liệu tới nơi, nó sẽ lên schedule cho CB được thực hiện bằng cách thêm CB vào event loop.
Chúng ta sẽ mô tả kĩ hơn event loop thông qua đoạn mã giả sau:
1: // `eventLoop` is an array that acts as a queue (first-in, first-out)
2: var eventLoop = [ ];
3: var event;
4: // keep going "forever"
5: while (true) {
6: // perform a "tick"
7: if (eventLoop.length > 0) {
8: // get the next event in the queue
9: event = eventLoop.shift();
10: // now, execute the next event
11: try {
12: event();
13: }
14: catch (err) {
15: reportError(err);
16: }
17: }
18: }
Event loop hoạt động như một hàng đợi queue bên trong một vòng lặp liên tục while-true, mỗi khi hàng đợi có ít nhất 1 event (eventLoop.length > 0) thì event đó sẽ được lấy ra khỏi hàng đợi và được thực hiện. Event này chính là hàm callback hay chính là thằng CB ở ví dụ trên.
2. Các khái niệm xung quanh Event loop
Vùng nhớ Heap: Là vùng nhớ không có cấu trúc, nơi các object JS được cấp phátVùng nhớ Stack: Là vùng nhớ làm nên tính single-threaded của JS, đây chính là nơi các function đc thực thi
Browser và WebAPI: được tích hợp sẵn có trong trình duyệt, có khả năng lấy dữ liệu từ trình duyệt và môi trường xung quanh để sử dụng
Callback queue: Hàng đợi chứa các callback (cách mà event loop hoạt động)
Sau khi đã nắm được các khái niệm, chúng ta sẽ đi tìm hiểu xem event loop vận hành thực tế với các câu lệnh như thế nào?
3. How Event loop work?
Để hiểu rõ hơn các hoạt động của event loop thế nào ta sẽ đi qua 2 ví dụ sau:
Ví dụ 1: Ta có đoạn code sau:
1: function main(){
2: console.log(1);
3: setTimeout(
4: function display(){ console.log(2); }
5: ,0);
6: console.log(3);
7: }
8: main();
Bước 1: Push main() vào trong Stack, bắt đầu thực hiện bên trong hàm main().
- Stack: main()
- Queue: null
- Output: <empty>
- Stack: main(), console.log(1)
- Queue: null,
- Output: 1
- Stack: main()
- Queue: null,
- Output: 1
- Stack: main(), setTimeout()
- Queue: null,
- Output: 1
- Stack: main()
- Queue: console.log(2),
- Output: 1
- Stack: main(), console.log(3)
- Queue: console.log(2),
- Output: 1<\n>3
- Stack: main()
- Queue: console.log(2),
- Output: 1<\n>3
- Stack: null
- Queue: console.log(2),
- Output: 1<\n>3
- Stack: console.log(2)
- Queue: null
- Output: 1<\n>3<\n>2
- Stack: console.log(2)
- Queue: null
- Output: 1<\n>3<\n>2
1
3
2
Kết
Event loop là cơ chế giúp JS hiện thực concurency mặc dù bản thân JS là single threaded. Nhờ có event loop thì chúng ta có thể thực hiện được các lời gọi hàm bất đồng bộ trên JS như fetch dữ liệu từ server hay đọc data từ ổ cứng...
Cảm ơn mọi người đã dành thời gian đọc bài viết của mình. Nếu có ý kiến đóng góp thì đừng ngại comment phía dưới. Nếu thấy hay có thể chia sẻ cho mọi người cùng biết nhé.
PS: Các bạn có thể tìm hiểu thêm về callback trong NodeJS qua bài 1 bài viết của mình tại đây. ^^
Reference:
- You don't know JS series
- RisingStack
- https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and-its-metrics-c4907b19da4c
- https://medium.com/front-end-hacking/javascript-event-loop-explained-4cd26af121d4
- Một video rất hay về Event loop: What the heck is the event loop?
Advertisement