+33

Hiểu về cơ chế xử lý sự kiện Event Loop trong Javascript

Xin chào mọi người, hôm nay mình quay lại với một bài viết về Event Loop một trong những khai niệm vẫn còn khá mơ hồ và khó hiểu đối với những người mới làm quen với Javascript. Trước tiên hay nói một chút về Javascript ra đời năm 1996 sau đó 1 năm thì tổ chức ECMA dựa trên Javascript đưa qua quy chuẩn cho các ngôn ngữ Script language đó là sự ra đời của ECMAScript. Để hiểu sâu hơn về lịch sử mình sẽ có 1 bài viết về nó hôm nay mình sẽ đi sâu vào cơ thế hoạt động và cách Javascript thực hiện các sự kiện lặp như thế nào nha.

Vậy Event Loop là gì và tại sao chúng ta phải hiểu về cách hoạt động của nó? Như mọi người đã biết JS hoạt động đơn luồng, chỉ một nhiệm vụ được thực thi trong 1 lúc. Nó sẽ không là vấn đề gì nhưng thử tưởng tượng 1 task chạy 30 giây, và bạn có đến 30 task cứ phải chờ như vậy là một vấn đề cực lớn trong chương trình. Đặc biệt trong thời đại công nghệ lên ngôi không một ai muốn phí phạm thời gian chờ đợi một ứng dụng không đáp ứng hiệu năng và không phản hồi kết quả. May mắn trình duyệt đưa cho chúng ta chức năng đó là Web API bao gồm DOM API và Http Request,… giúp chúng ta tạo nên các tác vụ chạy bất đồng bộ, non-blocking. Ok bây giờ bắt đầu đi sâu hơn vào cơ chế hoạt động nhé, khi một hàm được gọi trong JS, hàm đó được thêm vào 1 vùng nhớ được gọi là call stack. Call stack là một phần của JS Engine không phải của Browser nhé mọi người. Nói về Stack chắc mọi người cũng hiểu cơ chế FILO (first in last out). Sau khi hàm đã được đẩy vào call stack, nó trả về giá trị thực thi sau đó được lấy ra khỏi stack để đẩy hàm tiếp theo vào.

Việc phản hồi hay giá trị trả về như các hàm setTimeout được cung cấp bởi Web API. Các hàm này cho phép chúng ta thực hiện các hàm callback, các hàm callback này được đẩy vào vùng Web API là nơi chứa các hàm mà Web API cung cấp ở đây nó sẽ chờ thời gian được set ví dụ 1 giây sau đồng thời phẩn hồi lại với stack pop hàm setTimeout ra khỏi Call Stack.

Trong Web API, có một đồng hồ tính giờ được chạy ngay khi các hàm setTimeout, setInterval được đẩy vào, các hàm callback được truyền vào lúc này sẽ không nhảy qua Call Stack ngay mà nó được chuyển vào một hàng đợi Queue chờ được gọi lại. Trước giờ mọi người vẫn hình dung cứ xong thời gian setTimeout thì hàm callback được gọi ngay nhưng nó vẫn phải nằm trong hàm đợi đấy nhé đế lượt mới được thực thi nếu chúng ta xếp chồng setTimeout, setInterval đó là lý do các hàm này chúng ta chỉ sử dụng khi cần thiết.

Đây là phần khó hiểu nhất nè: hàm callback đã được đẩy vào quêu vậy khi nào nó được gọi nếu như đầu bài chúng ta đã nói hàm chỉ thực hiện trong vùng Call Stack? Đây là lúc Event Loop hoạt động, Event Loop có một nhiệm vụ duy nhất là đồng bộ Queue với Call Stack. Nếu Call Stack trống thì chúng ta gọi hàm trong Queue, Queue hoạt động theo cơ chế FIFO nên hàm nào nằm trong hàng đợi trước thì được gọi thực thi trong Call Stack trước. Mọi người lưu ý lúc này Call Stack trống thì các hàm trong Queue mới được Event Loop lấy lên và đẩy vào Call Stack để thực thi nhé.

Hàm callback sau khi đẩy vào Call Stack thì nó thực thì chờ trả về giá trị và lấy ra khỏi Call Stack cho việc thực hiện các hàm tiếp theo.

Ok chúng ta đã hiểu quy trình vây bây giờ hãy thử áp dụng một ví dụ nhé:

const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");

bar();
foo();
baz();

Thứ tự thực hiện như sau:

  1. Gọi hàm bar chờ bar trả về một hàm setTimeout
  2. Hàm callback được gọi khi truyền vào setTimeout, hàm callback được thêm vào vùng Web API, hàm setTimeout thực thi xong và bar được lấy ra khỏi Call Stack.
  3. Timer chạy trong Web API hết thời gian chúng ta thiết lập khi đó hàm foo được gọi và in log “First”. Hàm foo trả về “undefined”, baz sẽ được gọi và callback được thêm vào hàng đợi Queue.
  4. baz in log “Third”. Event Loop sẽ quan sát Call Stack xem nó trống hay không nếu trống sẽ lấy hàm trong Queue đưa vào Call Stack.
  5. Callback được gọi in log “Second”.

Trên đây là toàn bộ cơ chế và quy trình hoạt động của Event Loop, hi vọng tương lai mình có thể chia sẻ các bài viết hay hơn về Javascript. Cảm ơn tất cả mọi người đã đọc bài viết nhé ^^. Nguồn tham khảo:

  1. https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif – tác giả: Lydia Hallie
  2. https://gociter.wordpress.com/2019/12/08/hieu-ve-co-che-xu-ly-su-kien-event-loop-trong-javascript/

All rights reserved

Bình luận

Đăng nhập để bình luận
Avatar
@tranxuanthang
thg 12 18, 2019 12:50 SA

Bài viết rất hữu ích ạ, hơi khó hiểu 1 chút

Avatar
@congpc
thg 2 27, 2020 6:59 SA

Bài viết quá tuyệt vời. Cảm ơn bác nhé.

Avatar

Hay quá bác ❤️

Avatar
@taitrd
thg 7 23, 2021 11:53 SA

Cảm ơn bạn, mô tả sinh động dễ hiểu

Avatar
@phuoctn412
thg 3 20, 2023 12:44 SA

Thank you so much😘

Avatar

sao hàm foo trả về undefined mà hàm baz không trả về nhỉ? bản chất 2 hàm này giống nhau mà

Avatar
@hieu_db_d1
thg 4 9, 2024 3:35 SA

Tất cả mọi thứ đều ổn cho đến khi undefined xuất hiện 😦 Mình cứ ngỡ là mình hiểu sai, cho đến khi mình test 1 câu console.log("hello") thì thấy rằng sau khi print-> hello thì nó sẽ dính theo 1 cái undefined image.png Mình ngay lật tức nghĩ đến "tính năng của console" và search thì kết quả ntn: https://sobitprasad.hashnode.dev/why-do-browser-consoles-return-undefined-explained đại ý là khi ta hoàn thành 1 nhóm câu lênh(bằng việc ấn enter) thì trình duyệt sẽ in ra kết quả của nhóm câu lệnh đó.( console.log("hello") ko trả về gì cả thì mặc định là underfined, ai code API mà lâu lâu quên return như mình sẽ hiểu) image.png ok, vậy tóm lại underfined sau "Third" là do console của trình duyệt, nếu ta test bằng node thì sẽ ko bị như vậy image.png Bonus: nếu bạn thử 2+2 trên console thì nó sẽ log kết quả luôn thay vì undefined, ok vậy nên mình thêm 2+2 vô cuối để nó in ra số thay vì undefined image.png

Hi vọng những bạn đọc bài viết này sẽ hiểu vì sao undefined 😃

Avatar
+33
Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí