- vừa được xem lúc

Event Loops

0 0 5

Người đăng: soluho

Theo Viblo Asia

Javascript là một ngôn ngữ lập trình duy nhất ở thời điểm hiện tại có thể chạy trên trình duyệt web ( WA - Web assembly có thể chạy trên browser, web assembly khiến cho binary code có thể chạy trên nền web). Duy nhất ở đây không phải là không thể tạo ra ngôn ngữ nào khác thay thế mà là không cần thiết vì Javascript đã quá trở nên phổ biến (ở đây tập trung nói về client-side Javascript). Javascript được thiết kế theo event-driven paradigm (Hướng sự kiện). Javascript không phải là ngôn ngữ duy nhất được thiết kế dựa trên paradigm này (Hầu hết các ngôn ngữ hỗ trợ xây dựng GUI đều hỗ trợ).

Event-driven Paradigm

Giống như OOP được thiết kế dựa trên các Object & Class thì event-driven programming language được thiết kế dựa trên thành phần chủ yếu là Event & Listener. Đa phần các ngôn ngữ lập trình có thể xây dựng ứng dụng (application) đều hỗ trợ paradigm (Java, C, C++, et cetera). Lưu ý rằng là application ở đây không chỉ nói riêng về các GUI ở phía client mà còn cả ở phía server, vì server cũng phải luôn lắng nghe các request từ internet (dễ dàng mở rộng, tích hợp). Các ngôn ngữ lập trình đã hỗ trợ các event built-in (click, nhập liệu, di chuyển chuột, đọc file, xoá file, et cetera).

Event Emitters / Event Listeners

Event có rất nhiều loại, tuy nhiên ta có thể khái quát lại thế giới của event-driven paradigm gồm : emitters & listeners. Một event được định nghĩa là một hành động nào đó xảy ra, khi các điều kiện phù hợp với một tiêu chuẩn nào đó , event đó sẽ emit ra một tín hiệu (signal) đến cho nhiều listener đang chờ đợi tín hiệu đó. Khi nhận được các tín hiệu thì các listener sẽ được thực thi. Thông thường listener là các hàm (callback) đã được khai báo sẵn, khi nhận được tín hiệu thì sẽ lập tức thực thi. Điều này cho phép ta sắp đặt các listener phù hợp với tương ứng với các event. Ví dụ như khi người dùng click nút Mua thì ta sẽ lập tức hiển thị lên thông tin về giao dịch, ...

Ta cũng có nhiều vấn đề phát sinh như sau:

  • Event emit tín hiệu khi chương trình kết thúc thì như thế nào?
  • Làm sao chúng ta biết được khi nào một Event emit tín hiệu?
  • Lúc nhận được tín hiệu mà chúng ta đang thực hiện đoạn code khác thì sao?
  • ...

Thông thường đối với vấn đề thứ nhất và thứ hai, ta sẽ chọn cách giải quyết là để chương trình luôn chạy, luôn luôn khiến các listener ỏ trong trạng thái sẵn sàng (mặc dù đã hết phần code ở phần main) tín hiệu từ Event. Vấn đề thứ ba ta có thể sử dụng đa luồng để giải quyết.

Nói về lợi ích của event-driven paradigm, đơn giản và dễ mở rộng. Nói về vấn đề mua hàng, ta có thể mở rộng bằng cách thêm các listener đảm nhận chức năng sign up/sign in vào mà không ảnh hưởng tới code của việc thực hiện giao dịch, giúp chúng ta tracing (theo dấu) được các hành vi của người dùng một cách tốt hơn.(Khi người dùng hoàn thành )

Event Loops

Tổng kết lại, một hành động listener sẽ được thực thi khi một sự kiện event nào đó được xảy ra (không nhất thiết từ phía người dùng). Để các event & listener chạy đúng đắn (event này xảy ra thì listener này được thực hiện, et cetera) thì chương trình cần phải chạy liên tục, luôn luôn chờ signal từ các event emitter (nguồn phát tín hiệu báo sự kiện hoàn thành ) để có thể thực hiện các listener. Event Loops là cơ chế giúp javascript có thể luôn chờ các tín hiệu phát ra, và điều phối thứ tự thực hiện các listener của nhiều event khác nhau. Event Loops giống một đứa con nít luôn hỏi mẹ "Mẹ ơi khi nào về?", chỉ khác thứ Event Loops yêu cầu là tín hiệu của bất kỳ event. Javascript khi nhận được signal từ event emitter sẽ tìm kiếm đến các listener (một hàm callback) lắng nghe event và thực hiện (execute, call, invoke) nó.

Event loops - client side Event loops - nodejs

Điều đáng chú ý rằng javascript là một ngôn ngữ single thread (đơn luồng) dẫn tới việc javascript chỉ có 1 heap và 1 callstack (callback có thể sử dụng nhiều hàm chức năng khác nên callstack là cần thiết). Nếu nhiều event phát ra tín hiệu liên tiếp thì có cách giải quyết nào? Để giải quyết trường hợp này thì javascript hỗ trợ thêm khái niệm Event Queue, nhằm mục đích lưu trữ thứ tự các signal được emit từ các event khác nhau. Khi một listener được hoàn thành (thường là callstack trống), Event Queue sẽ lần lượt xử lý các listener tiếp theo.

Javascript lúc bình thường sẽ chạy từng dòng một từ trên xuống đồng bộ (synchronous), tuy nhiên khi các event phát ra signal thì phải được xử lý thông qua Event Queue (Từng event một sẽ được xử lý).

WebAPIs and Synchronous - Asynchronous

Synchronous nghĩa là đồng bộ, nhằm chỉ việc code của chúng ta sẽ được thực thi theo thứ tự nhất định (từng dòng 1). Khi gặp các tao thác I/O thì code sẽ bị block (không chạy phần phía dưới) cho đến khi I/O hoàn thành (điển hình là alert & prompt). Cơ chế event queue của javascript cũng được tính vào synchronous và asynchronous.

Xem xét ví dụ sau đây.

let btn = document.querySelector("#btn")
btn.addEventListener("click",()=>{ console.log("clicked")
})
btn.click() // thực hiện thao tác click vào nút, thay vì đợi người dùng click
console.log("he?")
// clicked
// he
// listener được execute trước!

Asynchronous nghĩa là bất đồng bộ, hằm chỉ việc code của chúng ta sẽ không được thực thi theo thứ tự đã viết. Xem xét ví dụ sau đây.

let btn = document.querySelector("#btn")
btn.addEventListener("click",()=>{ setTimeout(()=>{ console.log("clicked") },0)
})
btn.addEventListener("click",()=>{ console.log("clicked 2")
})
btn.click() // thực hiện thao tác click vào nút, thay vì đợi người dùng click
console.log("he?")
// clicked 2
// he
// clicked
// listener được execute sau!

Lí giải tại sao ví dụ thứ 2 lại có kết quả như vậy là bởi vì có sự can thiệp của Web API. WebAPI hỗ trợ chúng ta nhiều thứ như ajax, timers, file reader, et cetera. Về mặt bản chất thì Web API cũng hoạt động dựa trên event queue, tuy nhiên hơi khác một tí là: Nếu sử dụng Web APIs thì thứ tự ưu tiên của event được emit từ Web APIs sẽ "kém hơn" các event, nghĩa là Event sẽ bị hoãn cho tới khi callstack trống (code của chương trình chính được chạy hoàn toàn) thì mới được đưa vào Event Queue và bắt đầu xử lý theo quy tắc của Event Queue( lấy từng Event ra -> tạo callstack mới -> execute listener).

Hãy thử đoạn code trên với vòng lặp for dùng để blocking khoảng 2s

let btn = document.querySelector("#btn")
btn.addEventListener("click",()=>{ setTimeout(()=>{ console.log("clicked") },0)
})
btn.addEventListener("click",()=>{ console.log("clicked 2")
}) btn.click() // thực hiện thao tác click vào nút, thay vì đợi người dùng click
for(let i = 0;i<3000000000;i++){
// block 3s
}
console.log("he?")
// clicked 2
// Phải đợi khoảng 3s, mặc dù hàm setTimeout có thời gian đợi là 0s!
// he
// clicked

Những tác vụ có sử dụng Web APIs được gọi là những tác vụ asynchronous (điều ngược lại không đúng). Các tác vụ asynchronous (thường là function) sẽ có độ ưu tiên kém (chỉ được thêm vào event queue khi callstack trống lần đầu tiên - Hoàn thành hết code synchronous). Sau đó thì cũng sẽ được xử lý dưới cơ chế event queue & event loops. Sau khi đã qua hoàn thành code javascript synchronous thì mọi thứ (tức là tới cuối file script.js) thì mọi thứ sẽ được nhường về cho Event Loops và những thứ liên quan.

Đây cũng chính là sức mạnh của Javascript khi so sánh với các ngôn ngữ khác!

Tổng kết lại, event loops sẽ xem xét xem thử có bất kỳ event nào phát ra tín hiệu không? Nếu có thì sẽ thêm vào event queue. Nếu callstack trống, event queue sẽ xử lý từng listener tương ứng với signal được event phát ra. WebAPIs cung cấp cho chúng ta các công cụ tiện lợi(timers, fetch, file reader, et cetera) và hoạt động dựa vào event loops! Tuy nhiên WebAPIs bao gồm nhiều hành động asynchronous, kỹ năng xử lý hành động asynchronous rất quan trọng khi làm việc với Javascript.


References & more resources

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 502

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 415

- vừa được xem lúc

Một số phương thức với object trong Javascript

Trong Javascript có hỗ trợ các loại dữ liệu cơ bản là giống với hầu hết những ngôn ngữ lập trình khác. Bài viết này mình sẽ giới thiệu về Object và một số phương thức thường dùng với nó.

0 0 137

- vừa được xem lúc

Tìm hiểu về thư viện axios

Giới thiệu. Axios là gì? Axios là một thư viện HTTP Client dựa trên Promise.

0 0 120

- vừa được xem lúc

Imports và Exports trong JavaScript ES6

. Giới thiệu. ES6 cung cấp cho chúng ta import (nhập), export (xuất) các functions, biến từ module này sang module khác và sử dụng nó trong các file khác.

0 0 94

- vừa được xem lúc

Bài toán đọc số thành chữ (phần 2) - Hoàn chỉnh chương trình dưới 100 dòng code

Tiếp tục bài viết còn dang dở ở phần trước Phân tích bài toán đọc số thành chữ (phần 1) - Phân tích đề và những mảnh ghép đầu tiên. Bạn nào chưa đọc thì có thể xem ở link trên trước nhé.

0 0 230