Contents

Giới thiệu về lập trình hướng sự kiện trong Node.js

Bài học chính

Lập trình hướng sự kiện là một cách tiếp cận lý tưởng để phát triển các ứng dụng tương tác, đặc biệt là các ứng dụng có giao diện người dùng đồ họa (GUI), vì nó cho phép mã phản ứng với các tương tác của người dùng theo cách không thể đoán trước. Tính linh hoạt này đáp ứng các cách đa dạng mà người dùng có thể tương tác với ứng dụng và cung cấp trải nghiệm đáp ứng nhu cầu của họ một cách liền mạch.

Lập trình hướng sự kiện đã trở thành một phương pháp phổ biến trong các ứng dụng web, trong đó trình xử lý sự kiện được kích hoạt khi người dùng tương tác với Mô hình đối tượng tài liệu (DOM).

Việc kết hợp lập trình dựa trên sự kiện trong Node.js có thể đạt được một cách liền mạch thông qua việc sử dụng lớp EventEmitter, tạo điều kiện thuận lợi cho việc tạo ra các lần xuất hiện phù hợp và đính kèm trình xử lý sự kiện để quản lý phù hợp.

Khi phát triển một ứng dụng phần mềm, việc lựa chọn mô hình lập trình phù hợp là một quyết định cần thiết phải được thực hiện. Mô hình cuối cùng ảnh hưởng đến cấu trúc và tổ chức của mã, cũng như tính hiệu quả và khả năng bảo trì của nó. Do đó, điều quan trọng là phải xem xét cẩn thận mô hình nào phù hợp nhất với các yêu cầu và mục tiêu cụ thể của dự án trước khi thực hiện một cách tiếp cận cụ thể.

Lập trình hướng sự kiện, được đặc trưng bởi khả năng đáp ứng của nó đối với các sự kiện không đồng bộ xảy ra theo trình tự không thể đoán trước, đặc biệt phù hợp với các ứng dụng yêu cầu tương tác với người dùng và thường thấy trong giao diện người dùng đồ họa thay vì các chương trình dòng lệnh hoặc mã hóa hệ thống nhúng.

Sự kiện là gì?

Một sự kiện có thể được khái niệm hóa như một trường hợp thực thi do chương trình khởi xướng hoặc một kích thích khơi gợi phản ứng từ phần mềm, sau đó được xác định và xử lý bởi một thành phần chức năng được chỉ định trong mã. Thông thường, người dùng hoặc chính hệ thống sẽ kích hoạt một sự kiện, nhắc mã chỉ định một quy trình cụ thể để xử lý kết quả.

Trong lĩnh vực lập trình máy tính, một sự xuất hiện thô sơ sẽ được minh họa bằng quá trình nhấn một phím trên bàn phím để thực hiện một tác vụ cụ thể. Khi thao tác này diễn ra, nó sẽ kích hoạt một sự kiện được gọi là “sự kiện”, sau đó kích hoạt một chương trình con được gọi là “người nghe” hoặc “người xử lý”.

Lập trình hướng sự kiện là gì?

Lập trình hướng sự kiện có thể được mô tả như một cách tiếp cận cụ thể để phát triển phần mềm, trong đó tiến trình hoạt động của ứng dụng phụ thuộc vào các lần xuất hiện hoặc sự kiện cụ thể, thay vì tuân theo một trình tự tuyến tính và được xác định trước.

Mô hình cụ thể này thường được sử dụng trong quá trình phát triển giao diện người dùng và ứng dụng thời gian thực, trong đó hành động của người dùng dùng để bắt đầu phản hồi tương ứng từ hệ thống.

Trong bối cảnh phát triển các ứng dụng web, việc sử dụng trình xử lý sự kiện đã trở thành một cách tiếp cận được áp dụng rộng rãi vì chúng được kích hoạt để phản hồi các tương tác của người dùng với Mô hình đối tượng tài liệu (DOM).

Hình minh họa nói trên tóm tắt cơ chế cơ bản của lập trình hướng sự kiện, trong đó khi xảy ra một sự kiện, kênh sự kiện tương ứng sẽ được kích hoạt để truyền sự kiện nói trên đến người nghe được chỉ định để xử lý.

/vi/images/event_driven_visualization.jpg

Lập trình hướng sự kiện trong Node.js

Vòng lặp sự kiện trong JavaScript, tạo thành nền tảng cho đặc tính không đồng bộ của thời gian chạy Node.js, sử dụng kiến ​​trúc hướng sự kiện vốn có của nó bằng cách tận dụng mô-đun EventEmitter tích hợp để đảm bảo tiến trình hoạt động không bị gián đoạn và hiệu quả.

Bằng cách sử dụng cách tiếp cận theo hướng sự kiện, Node.js cho phép phát triển các ứng dụng dựa trên máy chủ có khả năng hỗ trợ khả năng tương tác của người dùng, hoạt động đầu vào/đầu ra và xử lý dữ liệu theo thời gian thực, tất cả đều không có cơ chế chặn tắc nghẽn, từ đó tối ưu hóa hiệu quả tổng thể và mang lại sự liền mạch Kinh nghiệm người dùng.

Việc triển khai lập trình hướng sự kiện trong Node.js có thể là một quá trình đơn giản khi người ta hiểu biết toàn diện về các nguyên tắc cơ bản liên quan đến việc xác định, kích hoạt và quản lý sự kiện.

Lớp EventEmitter

Việc sử dụng lớp Trình phát sự kiện trong Node.js cho phép tạo các sự kiện tùy chỉnh và tệp đính kèm của người nghe sự kiện để xử lý chúng. Để tích hợp mã lớp trong, nhập từ mô-đun sự kiện thông qua đặc điểm này:

 // CommonJS
const { EventEmitter } = require("events")

// ES6
import { EventEmitter } from "events" 

Khi một phiên bản của lớp EventEmitter đã được tạo, nó sẽ có thể truy cập được trong ứng dụng của bạn để sử dụng. Điều này cho phép bắt đầu các quy trình quản lý và phát sinh sự kiện.

Ví dụ:

 const FoodEvents = new EventEmitter()

việc sử dụng phương pháp’bật’, bổ sung trình nghe thông qua chiến lược’addListener’và kích hoạt phương pháp’một lần'.

Việc sử dụng thuộc tính on tạo thành thao tác cơ bản để kết hợp các trình xử lý sự kiện, với phương thức addEventListener() thể hiện khả năng nhận thông báo sự kiện giống hệt nhau. Cả hai cơ chế đều yêu cầu thông số kỹ thuật về lần xuất hiện được chỉ định cùng với chức năng riêng biệt đóng vai trò là thành phần phản ứng. Có thể sử dụng các lựa chọn thay thế này một cách liền mạch.

Để sử dụng phương pháp “bật” để quản lý một sự kiện cụ thể, hãy làm theo các bước sau:

 FoodEvents.on("cookie_ready", (data) => {
    console.log("Cookie ready for packaging, data received: ", data);
})

Thay vì sử dụng sự kiện “bật” trong JavaScript, người ta có thể sử dụng phương thức “addListener” để thay thế ngay lập tức.

 FoodEvents.addListener("cookie_ready", (data) => {
    console.log(
        "Cookie will now be packaged and sent out, data received: ",
        data
    );
})

Cả hai trường hợp thêm hàm gọi lại vào mảng trình xử lý sự kiện cho sự kiện “cookie\_ready” đều đảm bảo rằng chúng được thực thi tuần tự khi được kích hoạt. Việc gọi một trong hai dẫn đến việc thực thi chức năng gọi lại tương ứng của nó.

Việc triển khai chức năng này bao gồm việc đăng ký một trình xử lý sự kiện được kích hoạt khi xảy ra sự kiện được chỉ định cho một phiên bản duy nhất. Sau khi thực hiện thành công, trình xử lý sự kiện sẽ bị xóa khỏi danh sách trình xử lý hoạt động cho sự kiện cụ thể đó.

Để tạo điều kiện cho một trường hợp xảy ra đơn lẻ, hãy sử dụng mẫu Singleton kết hợp với vùng chứa Unity. Cách tiếp cận này đảm bảo rằng chỉ một phiên bản duy nhất của lớp dự định được tạo và duy trì trong suốt thời gian tồn tại của ứng dụng, quản lý hiệu quả phạm vi của sự kiện được đề cập.

 FoodEvents.once("cookie_sent", (data) => {
    console.log("Cookie is sent out, data received: ", data);
})

Trong trường hợp này, người gửi sẽ tham dự sự kiện cookie\_sent chỉ một lần và xóa chức năng gọi lại sau khi nó được thực thi.

Tất cả các kỹ thuật nói trên đều mang lại thực thể nguồn, do đó cho phép gọi liên tiếp bất kỳ phương thức đơn lẻ nào trong số chúng.

Hãy nhớ rằng để ai đó xử lý một sự kiện, ứng dụng tương ứng phải giải phóng nó bằng cách phát ra sự kiện nói trên vào một thời điểm nào đó. Phần sau đây cung cấp một ví dụ minh họa việc phát ra sự kiện cookie\_ready bằng cách sử dụng phương thức phát ra:

 function bakeCookie() {
    console.log("Cookie is baking, almost ready...")

    setTimeout(() => {
        FoodEvents.emit("cookie_ready", { flavor: "vanilla cookie" })
    }, 3000)
}

bakeCookie() 

Khi thực thi mã đã cho, hiển thị thông báo trong bảng điều khiển cho biết rằng cookie đang được chuẩn bị, tạm dừng trong ba giây và kích hoạt sự kiện cookie\_ready, người ta có thể mong đợi quan sát một biểu diễn trực quan tương tự như đồ họa được mô tả:

/vi/images/console_output.jpg

Ví dụ nói trên dùng để minh họa tiến trình theo trình tự thời gian của người nghe sự kiện, tuân theo trình tự đăng ký mà họ đã được đăng ký.

Lớp EventEmitter cung cấp nhiều phương thức hơn, bao gồm:

Hàm removeListener dùng để loại bỏ sự xuất hiện của một trình nghe khỏi tập hợp các trình xử lý sự kiện được liên kết với một thành phần hoặc đối tượng cụ thể, trong khi cách tiếp cận thay thế, off , cung cấp chức năng tương tự.

Phương thức prependListener được sử dụng để đăng ký một trình nghe với một trình phát sự kiện được chỉ định và đặt nó ở đầu danh sách các trình nghe cho sự kiện cụ thể đó. Không giống như phương thức addListener thêm các trình nghe mới vào cuối hàng đợi trình nghe hiện có, phương thức prependListener đảm bảo rằng trình nghe mới được thêm sẽ thực thi trước tất cả các trình nghe đã đăng ký trước đó.

Hàm prependOnceListener hoạt động tương tự như prependListener , với điểm khác biệt chính là trình nghe được chỉ định chỉ được thực thi một lần, tương tự như hành vi được thể hiện bởi phương thức một lần.

Hàm removeAllListeners dùng để loại bỏ tất cả những người đăng ký được liên kết với một lần xuất hiện được chỉ định cụ thể hoặc mọi người nghe trong trường hợp không có đối số nào được cung cấp.

Hàm người nghe trả về một mảng gồm tất cả các người nghe được liên kết với một sự kiện cụ thể, được truyền dưới dạng đối số cho hàm.

Đoạn mã được cung cấp cho phép truy xuất một mảng chứa tất cả tên sự kiện mà người nghe đã đăng ký trước đó.

Trong Node.js, thông lệ là giới hạn số lượng người nghe có thể đăng ký cho một sự kiện để tránh rò rỉ bộ nhớ. Theo mặc định, nền tảng sẽ đưa ra cảnh báo nếu có hơn 10 người nghe được thêm vào một sự kiện. Tuy nhiên, giới hạn này có thể được khắc phục thông qua việc sử dụng phương thức setMaxListeners. Ngoài ra, người ta có thể sử dụng hàm getMaxListeners để xác định số lượng người nghe tối đa hiện tại được phép cho một đối tượng cụ thể.

Gói sự kiện cung cấp một bộ tính năng mạnh mẽ được thiết kế để hỗ trợ lập trình dựa trên sự kiện trong môi trường Node.js.

Một số phương pháp hay nhất về lập trình theo hướng sự kiện là gì?

Khi xây dựng các hệ thống phần mềm dựa trên các sự kiện, điều cần thiết là phải thừa nhận những hạn chế tiềm ẩn liên quan đến từng phương pháp. Bỏ qua các kỹ thuật tối ưu có thể dẫn đến kết quả không thuận lợi cho chương trình của bạn. Với suy nghĩ này, đây là một số nguyên tắc chính cần ghi nhớ khi phát triển các ứng dụng dựa trên sự kiện:

Đảm bảo rằng việc đặt tên sự kiện vừa ngắn gọn vừa mang tính thông tin, nhằm thúc đẩy một môi trường lập trình được tổ chức tốt và dễ bảo trì.

Việc triển khai các kỹ thuật ghi nhật ký và xử lý lỗi hiệu quả là rất quan trọng trong việc tạo điều kiện thuận lợi cho quá trình khắc phục sự cố có thể phát sinh trong quá trình phát triển ứng dụng. Bằng cách triển khai các phương pháp hay nhất này, nhà phát triển có thể xác định và giải quyết hiệu quả mọi vấn đề xảy ra trong cơ sở mã của họ, từ đó đảm bảo trải nghiệm người dùng mượt mà và đáng tin cậy hơn.

Sử dụng các cấu trúc lập trình không đồng bộ, chẳng hạn như Promise và async/await, để giảm thiểu vấn đề về các lệnh gọi lại lồng nhau trong xử lý sự kiện. Cách tiếp cận này mang lại một giải pháp tinh tế hơn so với việc dựa vào các kỹ thuật lồng nhau rườm rà.

Bạn nên tránh thiết lập quá nhiều người nghe cho một sự kiện vì điều này có thể dẫn đến các vấn đề về hiệu suất. Thay vào đó, hãy cân nhắc việc chia nhỏ các sự kiện và liên kết chúng lại với nhau theo trình tự để đảm bảo hiệu quả tối ưu.

Xây dựng ứng dụng với kiến ​​trúc phù hợp

Khi xây dựng phần mềm, điều quan trọng là phải đưa ra các lựa chọn thiết kế và kiến ​​trúc sáng suốt để tránh những cạm bẫy tiềm ẩn trong tương lai. Việc không tuân thủ chiến lược phát triển hợp lý có thể dẫn đến những kết quả không mong muốn cho ứng dụng của bạn.

Lập trình hướng sự kiện là một triết lý thiết kế có thể ảnh hưởng sâu sắc đến cấu trúc và hiệu quả của ứng dụng. Nếu chương trình của bạn hoặc bất kỳ thành phần nào của nó dựa vào các sự kiện để vận hành thì lập trình hướng sự kiện có thể đáng được xem xét như một phương pháp phù hợp.