Kiến trúc Node.js - Event Loop

Kiến trúc Node.js - Event Loop

Những mẩu tin ngắn hàng ngày dành cho bạn
  • Hẳn là nhiều người ở đây đã nghe đến kiểu tấn công bảo mật Clickjacking rồi nhỉ. Kẻ tấn công thường nhúng một website (thường là mục tiêu) vào trong một iframe trên website của chúng, sau đó làm mờ hoặc ẩn nó đi rồi đặt vào vị trí các nút bấm trên web, ví dụ "Bấm vào để nhận quà". Đâu ai ngờ rằng phía trên nút bấm đó là một nút bấm khác trong iframe. Khá nguy hiểm!

    Nhưng trình duyệt đã có cách ngăn chặn kiểu tấn công này bằng các quy tắc như tiêu đề X-Frame-Options, frame-ancestors của CSP và SameSite: Lax/Strict của Cookies...

    Mới đây, đã xuất hiện thêm kiểu tấn công mới - "DoubleClickjacking" 😨. Đại ý là "hắn" lợi dụng hành động double click để lừa người dùng bấm vào một nút mà hắn muốn. Chi tiết hơn trong bài viết này: DoubleClickjacking: A New Era of UI Redressing.

    » Xem thêm
  • Mọi người đã nghe nói đến Jujutsu - jj - một dạng quản lý phiên bản cho mã nguồn (version control system) chưa? Có vẻ như nó đang nhận được nhiều sự quan tâm.

    Chờ xíu! Chẳng phải git đã quá tốt rồi sao? Thế thì chế ra thằng jj để làm gì nữa? Cũng hơi khó trả lời nhỉ? Mỗi công cụ sinh ra chắc chắn phải cải thiện hoặc khắc phục được nhược điểm của cái trước. Cho nên jj ắt hẳn phải làm được điều gì đó mà git chưa làm được nên mới nổi lên như vậy.

    Thật ra mình đã nghe nói đến jj từ vài tháng trước rồi, nhưng vào đọc thì toàn kiến thức cao siêu. Hoặc là đang mang nặng cái lối suy nghĩ của git vào trong đầu rồi nên chưa lĩnh hội ra được điều gì cả.

    Mình hay có kiểu cái gì đọc lần 1 mà không hiểu thì đọc tiếp lần 2, lần 2 không hiểu thì đọc tiếp lần 3... đến lần thứ n mà vẫn không hiểu thì bỏ. Cơ mà không phải là từ bỏ mà một thời gian sau đó quay lại đọc tiếp. Đến một lúc nào đó khả năng mình sẽ hiểu ra một ít vấn đề, thế mới tài 😆.

    Thì cái jj này có vẻ như nó đang mở ra được tính linh hoạt trong việc "cam kết" mã. Tưởng tượng bạn đang làm việc trên một dự án, đang ở nhánh này, muốn sang nhánh khác để sửa, nhưng mà lại đang viết dở ở nhánh này, thế là phải stash, rồi checkout, rồi commit, rồi merge hoặc rebase lại vào nhánh cũ... nhìn chung quá trình làm việc với git nghiêm ngặt đến mức cứng nhắc, cần nhiều thao tác để giải quyết một vấn đề, chưa kể cái cây commit (commit-tree) nữa thì ôi thôi, khỏi xem cho đỡ nhức mắt. Thế nên ông jj này đang làm cách nào đó để bạn khỏi cần phải quan tâm đến các nhánh luôn, sửa trực tiếp vào commit. Nghe ảo nhỉ 😂.

    Đấy mới lĩnh hội được đến đấy, hy vọng sau n lần đọc lại nữa mình sẽ viết được một bài chi tiết hơn về công cụ này.

    » Xem thêm
  • Gòi gòi tới công chiện gòi 🤤🤤🤤

    » Xem thêm

Các pha (Phases) của Event Loop

Trước đây, người ta đã đề cập rằng Event Loop sẽ giám sát Call Stack có đang trống hay không và Event Queue có đang chứa các hàm đang chờ xử lý hay không để thực hiện việc đưa chúng trở lại Call Stack. Quy trình này được thực hiện theo các giai đoạn như sơ đồ sau:

Các pha (Phases) của Event Loop

  • Timers: thực thi các hàm callback đã được lên lịch với setTimeout và setInterval.
  • I/O callbacks: thực hiện hầu hết tất cả các lệnh gọi lại ngoại trừ close callback, timers callback và setImmediate().
  • Idle, prepare: dùng cho việc xử lý nội bộ của node.js.
  • Poll: truy xuất các sự kiện I/O mới chấp nhận các kết nối đến và xử lý dữ liệu.
  • Check: xử lý hàm callback của setImmediate.
  • Close callbacks: thực thi các hàm callbacks cho các sự kiện close. Ví dụ: socket.on("close").

Điều này chứng minh các giai đoạn của Event Loop được thực thi bởi luồng chính. Mỗi giai đoạn thể hiện cách Event Loop quyết định việc đưa hàm callback nào đang chờ vào Call Stack để chúng được thực thi.

Các pha của Event Loop cũng là nguyên nhân dẫn đến thứ tự thực hiện của một số hàm trong node.js như setTimeout(cb, 0), setImmediate(), process.nextTick(cb) mà chúng ta sẽ tìm hiểu kỹ hơn về chúng trong một bài viết sau.

Tổng kết lại

Tóm lại thì node.js có 2 thành phần cấu tạo quan trọng:

Libuv - I/O không đồng bộ đa nền tảng

libuv là một thư viện hỗ trợ đa nền tảng, tập trung vào I/O không đồng bộ. Nó chủ yếu được phát triển để được sử dụng bởi node.js.

Libuv bao gồm vòng lặp sự kiện (Event Loop), TCP/UDP không đồng bộ, xử lý tệp không đồng bộ, nhóm luồng, các quy trình con và xử lý chúng một cách độc lập.

V8 JavaScript Engine

V8 là dự án open-source của Google, được viết bằng C++. Nó được sử dụng trong Chrome và Node.js.

Nó triển khai ECMAScript và WebAssembly, đồng thời chạy trên Windows 7 trở lên, macOS 10.12+ và Linux.

V8 chứa các khả năng phân bổ bộ nhớ heap, thực thi Call Stack, trình thu gom rác, trình biên dịch tối ưu hóa và trình thông dịch Javascript.

Node.js sử dụng V8 Javascript Engine và do đó còn được gọi là V8 embedder. Theo yêu cầu của V8 Engine, embedder phải triển khai một vòng lặp sự kiện. Node.js đã chọn libuv để triển khai vòng lặp. Đây là nơi V8 và libuv được kết nối bằng cách sử dụng các liên kết C++.

Là đơn luồng, node.js chỉ có một vòng lặp sự kiện. Giữa mỗi lần chạy vòng lặp sự kiện, node.js kiểm tra bất kỳ tác vụ I/O không đồng bộ nào đang chờ và kết thúc nếu không có bất kỳ sự kiện nào. Đơn giản là vòng lặp sự kiện không tạo ra ngay lập tức cho đến khi có callback đang chờ xử lý. Cuối cùng ứng dụng node.js kết thúc khi không có bất kỳ sự kiện nào trong Call Stack hoặc Event Queue.

Mô hình đồng thời chỉ với một luồng

Có thể tóm tắt về mô hình đồng thời trong luồng đơn, vòng lặp sự kiện (Event Loop) và ngăn xếp cuộc gọi (Call Stack) để xây dựng mô hình I/O không đồng bộ như sau:

  • Ứng dụng node.js được node.js thực thi.
  • Chức năng bị ràng buộc CPU (sử dụng CPU cao) được thực thi đồng bộ trên luồng chính.
  • Nếu chức năng là I/O không đồng bộ được đẩy tới nhóm luồng để thực thi không đồng bộ và luồng chính tiếp tục thực thi.
  • Sau khi chức năng không đồng bộ hoàn thành, nhóm luồng tự đẩy hàm callback và sự kiện vào Event Queue.
  • Vòng lặp sự kiện sử dụng luồng chính để theo dõi các hàm callbacks đang chờ xử lý trên Event Queue nếu Call Stack đang trống. Nó sẽ đưa các hàm callbacks vào lại Call Stack để thực thi nếu Call Stack trống.

Node.js nên dùng khi nào?

Node.js chỉ đơn giản là cung cấp mô hình I/O không đồng bộ, không bị chặn ngay cả với luồng đơn. Điều này làm cho node.js phù hợp hơn với các ứng dụng I/O chuyên sâu hơn. Các ứng dụng chuyên sâu về CPU sẽ không phù hợp với node.js vì nó sẽ chặn việc thực thi trên luồng đơn đó.

Vì ngôn ngữ lập trình Javascript được sử dụng trong node.js, các nhà phát triển có thể tạo các Application Stack đầy đủ chỉ bằng một ngôn ngữ Javascript.

Cao cấp
Hello

5 bài học sâu sắc

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (0)

Nội dung bình luận...
Bấm hoặc cuộn mạnh để sang bài mới