Contents
Call Stack là gì và nó có phải là thành phần của V8 NodeJS?
Call Stack chắc chắn là thành phần của V8 NodeJS rồi. Nó chính là cấu trúc dữ liệu mà V8 dùng để theo dõi các lệnh gọi hàm. Mỗi khi chúng ta gọi một function, V8 đặt một reference đến function đó bên trong 1 call stack và nó tiếp tục làm như vậy cho mỗi lần gọi lồng nhau của các function khác. Điều này cũng bao gồm các function tự gọi mình(đệ quy).

Khi các function gọi lồng nhau kết thúc, V8 sẽ bật một function tại một thời điểm và sử dụng giá trị trả về ở chỗ đó.
Vì sao điều này lại quan trọng cho việc hiểu về NodeJS? Bởi vì bạn chỉ có thể có MỘT Call Stack trong một process của NodJSe. Nếu giữ Call Stack đó busy, cái process Node đó cũng busy. Hãy nhớ lấy
Event Loop là gì? Nó có phải là thành phần của V8
Bạn nghĩ đâu là event loop trong cái diagram này?

Event Loop được cung cấp bởi thư viện libuv. Nó không phải là thành phần của V8
Vòng sự kiện là thực thể xử lý các sự kiện bên ngoài và chuyển đổi chúng thành lời kêu gọi gọi lại. Đó là một vòng lặp mà chọn các sự kiện từ hàng đợi sự kiện và đẩy callbacks của họ vào Call Stack. Nó cũng là một vòng lặp đa pha.
Event Loop là một thực thể xử lý các event ngoại vi và chuyển đổi chúng vào trong lời gọi callback. Nó là một vòng lặp chọn các event từ danh sách event đang chờ và đẩy callback của các event này vào Call Stack. Nó cũng là vòng lặp multi-phase
Nếu đây là lần đầu tiên bạn nghe về Event Loop, những định nghĩa này sẽ không hữu ích. Event Loop là một phần của bức tranh lớn hơn nhiều:

Bạn cần phải hiểu bức tranh lớn này để hiểu về Event Loop. Bạn cũng cần phải hiểu vị trí của V8, biết về Node APIs, và biết về cách nào mà những thứ được xếp vào hàng chờ để được thực hiện bởi V8
Node APIs là những function như setTimeout
or fs.readFile
. Bản thân nó không phải là một phần của Javascript. Chúng là những function được cung cấp bởi Node.
Event Loop ngồi ngay giữa của bức tranh(một phiên bản thực sự phức tạp hơn của nó) và hành động như một nhà tổ chức. Khi V8 Call Stack rỗng, event loop có thể quyết định những gì được thực thi tiếp theo
NodeJS sẽ làm gì khi Call Stack và hàng chờ event loop rỗng?
Nó chỉ đơn giản là exit.
Khi bạn chạy một chương trình Node, nó sẽ tự động khởi chạy event loop và khi event loop đó nhàn rỗi và chẳng còn gì để làm, process đó sẽ kết thúc.
Để giữ cho process Node tiếp tục chạy, bạn phải đặt một cái gì đó ở đâu đó trong hàng chờ event. Ví dụ, khi chạy một timer hoặc một server HTTP, về cơ bản bạn nói cho event loop biết rằng hãy tiếp tục chạy và kiểm tra những event này.
Bên cạnh V8 và Libuv, NodeJS còn có những dependency ngoại vi nào nữa?
Những thư viện sau mà Node process có thể sử dụng
- http-parser
- c-ares
- OpenSSL
- zlib
Tất cả chùng đều nằm bên ngoài Node. Chúng có mã nguồn riêng, license riêng. Node chỉ sữ dụng chúng thôi
Bạn phải nhớ điều này vì bạn cần biết cách mà những chương trình đang chạy. Nếu bạn nén dữ liệu, bạn có thể gặp rắc rối đâu đó trong thư viện zlib. Bạn sẽ đối mặt với lỗi trong zlib, không liên quan gì đến Node
Có thể chạy Node process nếu không có V8?
Đây có thể là câu hỏi mẹo. Bạn cần VM để chạy Node process, nhưng không chỉ V8, bạn có thể chạy với cả Chakra.
Vào Github repo này để theo dõi dự án node-chakra
Sự khác nhau giữa module.exports và exports?
Bạn luôn có thể dùng module.exports
để export ra API của các module. Cũng có thể sử dụng exports
trừ một trường hợp:
module.exports.g = ... // Ok
exports.g = ... // Ok
module.exports = ... // Ok
exports = ... // Not Ok
Vì sao ư?
exports
chỉ là reference hoặc alias của module.exports
. Khi thay đổi exports
bạn cũng đã thay đổi reference đó và không bao giờ thay đổi được API chính chủ ( module.exports
). Bạn chỉ nhận được một biến local trong phạm vi module.
Các biến top-level không phải là global?
Nếu bạn có module1
được đặt như là một biến top-level g
:
// module1.js
var g = 42;
Và bạn có module2
đang require module1
và thử truy cập vào biến g
, bạn sẽ nhận được g is not defined
.
Tại sao ư? Nếu làm điều tương tự trên trình duyệt, bạn có thể truy cập vào các biến top-level bên trong tất cả các script đã include phía sau định nghĩa của chúng.
Mỗi tập tin Node đều sở hữu IIFE (Immediately Invoked Function Expression) phía sau. Tất cả các biến được khai báo bên trong tập tin Node đều thuộc phạm vi của IIFE đó.
Câu hỏi liên quan: WhaOutput là gì nếu chạy tập tin Node với chỉ một dòng sau:
// script.js
console.log(arguments);
Bạn sẽ nhận được:

Vì sao?
Bởi vì những gì NodeJS chạy chính là function. NodeJS sẽ gói code của bạn thành function và chạy function đó .
Các đối tượng exports
, require
, và module
là global trong mọi tập tin nhưng lại khác nhau trong từng tập tin. Bằng cách nào?
Khi bạn cần dùng đối tượng require
, bạn chỉ cần dùng nó trực tiếp như thể nó là biến global vậy. Tuy nhiên, nếu xem xét require
trong hai tập tin, chúng lại là hai đối tượng khác nhau. Bằng cách nào?
Bởi vì IIFE:

exports
, require
, và module
Như bạn thấy, IIFE gắn vào code của bạn năm argument sau: exports
, require
, module
, __filename
, and __dirname
.
Năm biến này hiển thị là global khi dùng trong NodeJS, nhưng chúng thực ra chỉ là các argument của function
Circular dependency của module trong NodeJS là gì?
Nếu bạn có module1
require đến module2
và module2
lại require module1
, Chuyện gì sẽ xảy ra? Lỗi chăng?
// module1
require('./module2');
// module2
require('./module1');
Sẽ không có lỗi. NodeJS cho phép làm điều đó
Vì module1
require đến module2
, nhưng khi module2
cần module1
và module1
lại chưa xong, module1
sẽ chỉ nhận được một phần của module2
. Bạn hãy chú ý, vì điều này có thể dẫn đến “tràn ram” server của bạn – memory leak.
Khi nào thì sử dụng được các method *Sync (kiểu như readFileSync)
Mỗi phương thức fs
trong Node có một phiên bản bất đồng bộ. Vì sao bạn sẽ dùng một phương thức đồng bộ thay vì một phương thức bất đồng bộ?
Đôi khi dùng phương thức đồng bô sẽ tốt. Ví dụ, nó có thể dùng như một bước khởi tạo trong lúc chờ cho server load lên. Thường là trong trường hợp mà mọi bước sau đều phụ thuộc vào data mà bạn nhận được ở bước này. Sử dụng phương thức bất đồng bộ cũng được, miễn là cho những thứ làm chỉ trong một lần.
Tuy nhiên, sẽ rất sai nếu bạn dùng phương thức bất đồng bộ bên trong một xử lý request callback kiểu như HTTP server.
Kết luận
Qua bài viết bạn đã biết hơn những điều về NodeJS. Hãy tận dụng để tối ưu hóa code và app của bạn.
Để nâng cao thêm kiến thức về NodeJS, hãy tham khảo thêm 19 bí mật để trở thành dev NodeJS xịn xò 2020 – phần 1

Bài viết này được sưu tầm và tổng hợp từ nhiều nguồn trên Internet.
Nếu có gì không hiểu thì inbox messenger bên dưới mình hỗ trợ thêm nhé.
0 Comments