Mục lục bài viết
Cập Nhật: 2021-12-25 01:51:31,Bạn Cần biết về Event-Driven NodeJS là gì. Bạn trọn vẹn có thể lại Báo lỗi ở cuối bài để Mình được tương hỗ.
FacebookLinkedinTelegram
Tác giả: Giang Coffee
Tóm lược đại ý quan trọng trong bài
Trước đây thi thoảng có làm Javascript và cũng luôn có thể có nghe nói qua về một số trong những khái niệm cơ bản và hay ho của Javascript như nhân V8 của Google (quá oách), Event-Driven, Non-blocking I/O, Event Loop những khái niệm giúp JS tận dụng sức mạnh mẽ của phần cứng và hàng trăm quyền lợi khác. Dạo mới gần đây có làm nhiều về JS, gặp nhiều lỗi quái đản mình mới tự đưa ra vướng mắc là rốt cục toàn bộ những thứ trên là cái gì?, hoạt động giải trí và sinh hoạt thế nào? và tại sao nó mang lại quyền lợi?
Hôm nay qua một số trong những google search và đặc biệt quan trọng xem đượcbài thuyết trình này mình thấy Event Loop đó là thứ nguồn gốc, hay ho nhất và muốn san sẻ, thảo luận cùng mọi người. Đấy là những gì mình hiểu ra chứ chưa chắc đã là chuẩn xác. Anh em có gì góp ý mình cực kỳ hoan nghênh và tiếp thu.
Tất cả những ngôn từ lập trình đều được sinh ra để làm thứ ngôn từ tiếp xúc giữa người và máy. Dù là ngôn từ gì đi chăng nữa thì ở đầu cuối vẫn phải dịch ra mã máy, được load lên memory, chạy từng dòng lệnh, ghi những tài liệu trong thời gian tạm thời ra bộ nhớ, ổ đĩa rồi tiếp xúc những thiết bị ngoại vi Thế nên làm cho tiện mình xin nhắc lại một số trong những khái niệm cơ bản sau.
Stack là một vùng nhớ đặc biệt quan trọng trên con chip máy tính phục vụ cho quy trình thực thi những dòng lệnh mà rõ ràng là những hàm. Hàm chẳng qua là một nhóm những lệnh và chương trình thì gồm một nhóm những hàm phối thích phù hợp với nhau. Mỗi khi một hàm được triệu gọi thì nó sẽ tiến hành đẩy vào một trong những hàng đợi đặc biệt quan trọng mang tên là stack. Stack là một hàng đợi kiểu LIFO (Last In First Out) nghĩa là vào thứ nhất thì ra sau cùng. Một hàm chỉ được lấy thoát khỏi stack khi nó hoàn thành xong và return.
Nếu trong một hàm (Foo) có triệu gọi một hàm khác (Bar) thì trạng thái hiện tại của hàm Foo được cất giữ trong stack và hàm Bar sẽ tiến hành chèn vào stack. Vì đấy là hàng đợi LIFO nên Bar sẽ tiến hành xử lý trước Foo. Khi Bar xong và return thì mới có thể đến lượt Foo được xử lý. Khi Foo được xử lý xong và return thì Stack rỗng và sẽ đợi những hàm tiếp theo được đẩy vào.
Stack
——————–
| |
——————–
| Bar | <–
——————–
| Foo |
——————–
Heap là vùng nhớ được vốn để làm chưa kết quả tạm phục vụ cho việc thực thi những hàm trong stack. Heap càng lớn thì kĩ năng tính toán càng cao. Heap trọn vẹn có thể được cấp phép tĩnh hoặc cấp phép động bằng mấy lệnh kiểuallocvớimalloc(đấy là những gì còn nhớ về C++).
Event Loop là cơ chế giúp Javascript trọn vẹn có thể tiến hành nhiều thao tác cùng một lúc (concurrent model), trước giờ vẫn nghe nóiNodeJscó thể xử lý cả hàng nghìn request cùng một lúc tuy nhiên nó chỉ dùng một thread duy nhất (Single Threaded). Nếu như ở PHP hay Java thì với mỗi một request sẽ sinh ra một thread để xử lý request đó, những thread hoạt động giải trí và sinh hoạt độc lập, được cấp bộ nhớ, tiếp xúc ngoại vi và trả về kết quả. Vậy làm thế nào để NodeJs trọn vẹn có thể xử lý cả nghìn request một lúc với chỉ một thread duy nhất?.
Có một thực sự là trên web browser thì trong lúc get data từ những url thì người tiêu dùng vẫn trọn vẹn có thể tiến hành những thao tác khác ví như click button và gõ vào những ô textbox. Tất cả là nhờ có những web apis và cơ chế hoạt động giải trí và sinh hoạt của Event Loop. Tuy Js Runtime chỉ có một thread duy nhất nhưng những web apis giúp nó tiếp xúc với toàn thế giới multi thread bên phía ngoài, tận dụng những con chip đa nhân vốn rất phổ cập lúc bấy giờ. Web apis giúp đẩy những job ra bên phía ngoài và chỉ tạo ra những sự kiện kèm theo những handler gắn với những sự kiện. Kể cả so với NodeJs lúc không tồn tại web apis thì nó vẫn đang còn những cơ chế tương tự khác giúp đẩy job ra bên phía ngoài và chỉ quản trị và vận hành những đầu việc. Web Apis hoạt động giải trí và sinh hoạt như vậy thì Event Loop sẽ thế nào?
Event Loop mang tên như vậy chính vì có một vòng lặp vô tận trong Javascript Runtime (V8 trong Google Chrome) vốn để làm lắng nghe những Event.
while (queue.waitForMessage())
queue.processNextMessage();
Nhiệm vụ của Event Loop rất đơn thuần và giản dị đó là đọc Stack và Event Queue. Nếu nhận thấy Stack rỗng nó sẽ nhặt Event thứ nhất trong Event Queue và handler (callback hoặc listener) gắn với Event đó và đẩy vào Stack. Đặc điểm của việc thực thi hàm trong JS là sẽ chỉ tạm ngưng khi hàm return hoặc throw exception. Có nghĩa là trong lúc hàm đang hoạt động giải trí và sinh hoạt thì sẽ không còn tồn tại một hàm khác được chạy, tài liệu tạm của hàm cũng tiếp tục không còn trở thành thay đổi bởi một hàm khác hay cũng không trở thành tạm ngưng cho tới khi hoàn thành xong (ngoại trừyieldtrong ES6).
Như những bạn thấy trên hình thì JS Runtime còn thao tác với một callback queue hay sự kiện queue ngoài stack ra. Event queue này khác với stack ở đoạn nó là queue kiểu FIFO (First In First Out). Mỗi khi có một Event được tạo ra, ví dụ user click vào một trong những Button thì một Event sẽ tiến hành đẩy vào Event queue cùng với một handler (sự kiện listener) gắn với nó. Nếu một Event không tồn tại listener thì nó sẽ bị mất và không được đẩy vào Event queue. Để cho dễ tưởng tượng phương pháp hoạt động giải trí và sinh hoạt của Event Loop ta lấy một ví như sau:
const fs = require(‘fs’);
function someAsyncOperation(callback)
// giả sử đọc file hết 95ms
fs.readFile(‘/path/to/file’, callback);
const timeoutScheduled = Date.now();
setTimeout(function logInfo() =>
const delay = Date.now() – timeoutScheduled;
console.log(`$delayms have passed since I was scheduled`);
, 100);
// đọc file xong sẽ tiếp tục chờ thêm 10ms
someAsyncOperation(function readFileAsync() =>
const startCallback = Date.now();
// chờ 10ms
while (Date.now() – startCallback < 10)
// do nothing
);
thứ nhất phần khai báo biến và hàm sẽ tiến hành chạy nhưng không được đẩy vào stack. TiếpsetTimeout()sẽ tiến hành đẩy vào stack và tiến hành. Hàm này sẽ không tồn tại trong Javascript Runtime mà là hàm tiện ích của Browser, nó sẽ tạo một bộ đếm và sau đúng 100ms thì nó sẽ đẩy tham số đầu tiênlogInfo(là một callback hoặc trọn vẹn có thể gọi là một sự kiện listener cũng rất được) vào Event Queue. Kế đến sẽ chạy hàmsomeAsyncOperationvà đẩy vào stack, vì hàm này async và có callbackreadFileAsyncnênreadFileAsyncđược đẩy luôn vào Event Queue mà không phải chờ nhưsetTimeoutđể hứng sự kiện đọc xong file (sau 95ms).
Stack Event Queue
——————– ——————-
| | | readFileAsync | <–
——————– ——————-
| | | |
——————– ——————-
| someAsyncOperation | <– | |
——————– ——————-
Để ý là Stack LIFO nênsomeAsyncOperationsẽ nằm dưới cùng còn Event Queue FIFO nênreadFileAsyncsẽ nằm trên cùng. Sau khireadFileAsyncđược đẩy vào Event Queue thìsomeAsyncOperationreturn và được lấy thoát khỏi Stack. Lúc này Stack không tồn tại gì nênEvent Queuesẽ được đọc, nên nhớ làEvent Queuechỉ được đọc khi Stack trống rỗng.readFileAsyncsẽ được đẩy vàoEvent Queuetrước vì nó chỉ mất có 95ms trong khilogInfothì phải chờ 100ms.readFileAsyncnày sẽ tiến hành lấy khỏi Event Queue và đẩy vào stack để chạy.
Stack Event Queue
——————– ——————-
| | —— | readFileAsync |
——————– | ——————-
| | | | logInfo | <–
——————– | ——————-
| readFileAsync | <– | |
——————– ——————-
readFileAsyncsẽ gặp vòngwhilevà dừng ở đó 10ms. Vậy tổng số hàm đọc file sẽ mất 105ms để hoàn thành xong. Nhưng ở giây thứ 100 thìlogInfođược đẩy vào Event Queue (thời gian lúc bấy giờ đã rỗng) trong khireadFileAsyncthì còn phải mất thêm 5ms nữa mới hoàn thành xong. Vì cơ chế của Javascript là chạy đến khi hoàn thành xong mới thôi nênlogInfokhông có cách nào để dừngreadFileAsynclại để chiếm quyền điều khiển và tinh chỉnh, trừ khi trongreadFileAsynccó lệnhyield. Sau 105ms thìreadFileAsyncreturn và được lấy thoát khỏi Stack.
Stack Event Queue
——————– ——————-
| | —— | logInfo |
——————– | ——————-
| | | | |
——————– | ——————-
| logInfo | <– | |
——————– ——————-
Một lần nữa Stack lại trống vàlogInfođược đẩy vào Stack. Như vậylogInfosẽ phải đợi tổng số 105ms để được chạy, chứ không phải 100ms như dự trù. Do đó tham số thứ hai củasetTimeoutlà thời hạn tối thiểu để một Event được đẩy vào Stack và chạy chứ không phải là thời hạn đúng chuẩn nó sẽ tiến hành chạy.
Giả sử bạn có một đoạn code jQuery như sau:
$(‘#button_1’).click(function yield()
console.log(‘Ouch!’);
);
thì một hoặc vài sự kiện sẽ tiến hành đẩy vào Event Queue như sau:
Stack Event Queue
——————– ——————-
| | | yield(Event) | <–
——————– ——————-
| Bar | | |
——————– ——————-
| Foo | <– | |
——————– ——————-
đặt tên hàm làyieldchỉ nhằm mục tiêu mục tiêu dễ theo dõi, ta trọn vẹn trọn vẹn có thể bỏ tên hàm đi trong trường hợp này. Khi Bar và Foo return và được lấy thoát khỏi Stack thì yield sẽ tiến hành đẩy vào Stack với tham số là DOM Element xẩy ra sự kiện click.
Cơ chếrun to completioncủa Javascript có một điểm bất lợi đó là nếu một hàm chạy quá lâu hoặc bị vòng lặp vô tận thì sẽ không còn tồn tại hàm nào được chạy nữa, kết quả là Browser sẽ bị đơ, không phản ứng với những sự kiện như click chuột Ví dụ:
function foo()
console.log(‘i am foo!’);
foo();
foo();
hàm đệ quy không điểm dừng sẽ liên tục đẩyfoovào Stack cho tới khi đầy, và bạn đoán xem thời gian lúc bấy giờ toàn bộ chúng ta sẽ đã có được cái mà hằng ngày những develop đều tìm kiếmStack Overflow
Stack Event Queue
——————– ——————-
| foo | | Event 1 |
——————– ——————-
| foo | | Event 2 |
——————– ——————-
| foo | | Event 3 |
——————– ——————-
Để tránh tình trạng Browser bị treo vì lỗi lập trình thì những Browser sẽ throw exception trong trường hợp này:
MAXIMUM CALL STACK SIZE EXCEEDED.
Hầu hết những thao tác trong Javascript đều là sự không tương đồng điệu nhưng có một số trong những ngoại lệ thú vị như hàmalert(hàm này là của Browser API, không tồn tại trong NodeJs). Khi hàm này được chạy thì bạn không thể tiến hành một thao tác nào khác ngoài click OK.
Đến đây ta trọn vẹn có thể thấy cơ chế quản trị và vận hành theo đầu việc là bí kíp giúp JS Runtime trọn vẹn có thể xử lý hàng nghìn tác vụ cùng một lúc. Giống như bạn được giao một đống việc, bạn chia nhỏ từng việc và giao cho đám đệ tử của tớ.
Bài viết gốc được đăng tải tạiGiang Coffee
Tuyển lập trình viên Javascript lương cao tại đây
FacebookLinkedinTelegramBan Biên Tập Blog TopDev. Nice to meet you
Reply
6
0
Chia sẻ
– Một số từ khóa tìm kiếm nhiều : ” Review Event-Driven NodeJS là gì tiên tiến và phát triển nhất , Chia Sẻ Link Tải Event-Driven NodeJS là gì “.
Bạn trọn vẹn có thể để lại Comment nếu gặp yếu tố chưa hiểu nha.
#EventDriven #NodeJS #là #gì