sách gpt4 ăn đã đi

Hãy nói về cơ chế mô-đun của Node.js

In lại Tác giả: qq735679552 Thời gian cập nhật: 29-09-2022 22:32:09 32 4
mua khóa gpt4 giày nike

CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.

Bài viết trên blog CFSDN này nói về cơ chế module của Node.js. Nó được tác giả sưu tầm và biên soạn. Nếu các bạn quan tâm đến bài viết này thì nhớ like nhé.

Hãy nói về cơ chế mô-đun của Node.js

Lời nói đầu: Cơ chế mô-đun là một thành phần rất quan trọng trong Node.js. Cơ chế mô-đun cho phép chúng ta viết mã theo cách mô-đun thay vì viết tất cả mã vào một tệp. Chúng tôi thường sử dụng require để tải các mô-đun, nhưng có thể chúng tôi không rõ lắm về nguyên tắc triển khai require. Ngoài ra, có nhiều loại mô-đun trong Node.js và các nguyên tắc tải cũng khác nhau. cơ chế mô-đun js và nguyên tắc triển khai.

1 Khởi tạo và sử dụng cơ chế module

1.1 Đăng ký mô-đun C++.

Khi Node.js khởi động, mô-đun C++ sẽ được đăng ký thông qua RegisterBuiltinModules.

  1. void RegisterBuiltinModules() {   
  2.  #define V(tên mod) _register_##tên mod();   
  3.    NODE_BUILTIN_MODULES(V)   
  4.  #công đoàn V   

NODE_BUILTIN_MODULES là macro ngôn ngữ C. Macro được mở rộng như sau (loại bỏ logic tương tự).

  1. voidRegisterBuiltinModules() {   
  2.     #define V(tên mod) _register_##tên mod();   
  3.       V(tcp_wrap)    
  4.       V(bộ đếm thời gian)   
  5.       ...mô-đun khác   
  6.     #công đoàn V   

Việc mở rộng hơn nữa như sau.

  1. void RegisterBuiltinModules() {   
  2.   _register_tcp_wrap();   
  3.   _register_timers();   

Một loạt hàm bắt đầu bằng _register được thực thi, nhưng chúng tôi không thể tìm thấy các hàm này trong mã nguồn Node.js vì các hàm này được xác định thông qua macro trong các tệp được xác định bởi mỗi mô-đun C++ (dòng cuối cùng của tệp .cc). Lấy mô-đun tcp_wrap làm ví dụ để xem nó hoạt động như thế nào. Dòng mã cuối cùng trong tệp tcp_wrap.cc là phần mở rộng macro NODE_MODULE_CONTEXT_AWARE_INTERNAL(tcp_wrap, node::TCPWrap::Initialize).

  1. #define NODE_MODULE_CONTEXT_AWARE_INTERNAL(tên mod, regfunc) \   
  2.     NODE_MODULE_CONTEXT_AWARE_CPP(tên mod,  
  3.                                   chức năng điều chỉnh,  
  4.                                   giá trị rỗng,  
  5.                                   NM_F_BÊN TRONG) 

Tiếp tục mở rộng.

  1. định nghĩa NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \   
  2.   tĩnh node::node_module _module = { \   
  3.       PHIÊN BẢN_MÔ_ĐUN_NODE, \   
  4.       cờ, \   
  5.       giá trị rỗng, \   
  6.       __TÀI LIỆU__, \   
  7.       giá trị rỗng, \   
  8.       (node::addon_context_register_func)(regfunc), \   
  9.       NODE_STRINGIFY(tên mod), \   
  10.       riêng tư, \   
  11.       nullptr}; \   
  12.   void _register_tcp_wrap() { node_module_register(&_module); } 

Chúng ta thấy rằng lớp dưới cùng của mỗi mô-đun C++ xác định một hàm bắt đầu bằng _register. Khi Node.js khởi động, các hàm này sẽ được thực thi lần lượt. Hãy tiếp tục xem những hàm này làm gì. Trước đó, trước tiên chúng ta cần hiểu cấu trúc dữ liệu biểu thị các mô-đun C++ trong Node.js.

  1. cấu trúc node_module {   
  2.   số nguyên Phiên bản nm;   
  3.   chưa ký số nguyên cờ_nm;   
  4.   void* xử lý nm_dso;   
  5.   hằng số char* nm_tên_tệp;   
  6.   node::addon_register_func chức năng đăng ký nm;   
  7.   node::addon_context_register_func chức năng đăng ký_context nm;   
  8.   hằng số char* nm_tên_mod;   
  9.   void* nm_priv;   
  10.   cấu trúc node_module* nm_link;   
  11. }; 

Chúng ta thấy rằng hàm ở đầu _register gọi node_module_register và chuyển vào cấu trúc dữ liệu node_module, vì vậy chúng ta hãy xem cách triển khai node_module_register.

  1. void node_module_register(void* m) {   
  2.       cấu trúc node_module* mp = reinterpret_cast(m);   
  3.       nếu (mp->nm_flags & NM_F_INTERNAL) {   
  4.         mp->nm_link = modlist_internal;   
  5.         modlist_internal = mp;   
  6.       } khác nếu (!node_is_initialized) {  
  7.         mp->nm_flags = NM_F_LIÊN KẾT;   
  8.         mp->nm_link = danh sách modlist_liên kết;   
  9.         modlist_linked = mp;   
  10.       } khác {   
  11.         thread_local_modpending = mp;   
  12.       }   

Cờ của mô-đun tích hợp C++ là NM_F_INTERNAL, do đó logic của if đầu tiên sẽ được thực thi tương tự như một con trỏ đầu. Logic trong if là tạo một danh sách liên kết đơn thông qua việc chèn đầu.

1.2 Khởi tạo bộ nạp mô-đun.

Sau khi đăng ký mô-đun C++, hãy khởi tạo trình tải mô-đun.

  1. MaybeLocal Môi trường::BootstrapInternalLoaders() { 
  2.   EscapableHandleScope phạm vi(cô lập_); 
  3.  
  4.   // Katasan 
  5.   std::vector<Địa phương> loaders_params = { 
  6.       chuỗi_quy_trình(), 
  7.       FIXED_ONE_BYTE_CHUỖI_(cô lập_, "getLinkedBinding"), 
  8.       FIXED_ONE_BYTE_CHUỖI_(cô lập_, "getInternalBinding"), 
  9.       chuỗi_chính()}; 
  10.   // tham số thực tế 
  11.   std::vector<Địa phương> loaders_args = { 
  12.       tiến trình_đối_tượng(), 
  13.       NewFunctionTemplate(binding::GetLinkedBinding) 
  14.           ->GetFunction(bối cảnh()) 
  15.           .ToLocalChecked(), 
  16.       NewFunctionTemplate(bind::GetInternalBinding) 
  17.           ->GetFunction(bối cảnh()) 
  18.           .ToLocalChecked(), 
  19.       nguyên thủy()}; 
  20.  
  21.   //Thực thi nội bộ/bootstrap/loaders.js 
  22.   Địa phương loader_exports; 
  23.   nếu (!ExecuteBootstrapper( 
  24.            cái này, "nội bộ/khởi động/bộ tải", &loaders_params, &loaders_args) 
  25.            .ToLocal(&loader_exports)) { 
  26.     trở lại MaybeLocal(); 
  27.   } 
  28.   // ... 

Thực thiBootstrapper sẽ đọc nội dung của Internal/bootstrap/loaders.js và gói gọn nó thành một hàm như sau.

  1. chức năng (quy trình, getLinkedBinding, getInternalBinding, nguyên thủy) { 
  2.     // Nội dung của Internal/bootstrap/loaders.js 

Sau đó thực hiện tham số này và truyền vào bốn tham số thực tế. Chúng ta hãy xem nội bộ/bootstrap/loaders.js trả về những gì sau khi thực thi.

  1. const loaderExports = { 
  2.   //Tải mô-đun C++ 
  3.   liên kết nội bộ, 
  4.   // Trình quản lý mô-đun JS gốc 
  5.   Mô-đun gốc, 
  6.   // Trình tải JS gốc 
  7.   yêu cầu: nativeModuleRequire 
  8. }; 

Hai bộ tải mô-đun và một trình quản lý mô-đun đã được trả lại. Sau đó Node.js lưu chúng để sử dụng tiếp theo.

  1. // Lưu kết quả trả về của việc thực thi hàm 
  2. Địa phương loader_exports; 
  3. nếu (!ExecuteBootstrapper( 
  4.          cái này, "nội bộ/khởi động/bộ tải", &loaders_params, &loaders_args) 
  5.          .ToLocal(&loader_exports)) { 
  6.   trở lại MaybeLocal(); 
  7. Địa phương<đối tượng=""> loader_exports_obj = loader_exports.BẰNG<đối tượng="">(); 
  8. // Lấy trình tải mô-đun C++ 
  9. Địa phương internal_binding_loader = loader_exports_obj->Get(context(), internal_binding_string()) 
  10.         .ToLocalChecked(); 
  11. // Lưu trình tải mô-đun C++ set_internal_bind_loader(internal_bind_loader.BẰNG<Chức năng>()); 
  12. // Lấy trình tải JS gốc 
  13. Địa phương yêu cầu = loader_exports_obj->Get(context(), require_string()).ToLocalChecked(); 
  14. // Lưu trình tải JS gốc set_native_module_require(require.BẰNG<Chức năng>()); 

1.3 Thực thi JS của người dùng.

Sau khi khởi tạo Node.js, mã của người dùng cuối cùng sẽ được thực thi thông qua mã sau.

  1. Bắt đầu thực hiện(môi trường, "nội bộ/chính/run_main_module"

Hãy xem StartExecution.

  1. MaybeLocal StartExecution(Môi trường* env, const char* mã_lệnh_chính) { 
  2.   EscapableHandleScope phạm vi(env->isolate()); 
  3.   KIỂM TRA_KHÔNG_NULL(main_script_id); 
  4.  
  5.   std::vector<Địa phương> tham số = { 
  6.       env->process_string(), 
  7.       // yêu cầu hàm 
  8.       env->require_string(), 
  9.       env->internal_binding_string(), 
  10.       env->primordials_string(), 
  11.       FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")}; 
  12.  
  13.   std::vector<Địa phương> đối số = { 
  14.       env->process_object(), 
  15.       // Trình tải mô-đun JS và C++ gốc 
  16.       env->native_module_require(), 
  17.       env->internal_binding_loader(), 
  18.       env-> nguyên thủy(), 
  19.       env->NewFunctionTemplate(MarkBootstrapComplete) 
  20.           ->GetFunction(môi trường->bối cảnh()) 
  21.           .ToLocalChecked()}; 
  22.  
  23.   trở lại phạm vi.EscapeMaybe( 
  24.       ExecuteBootstrapper(env, main_script_id, ¶meters, &arguments)); 

Hai bộ tải được truyền vào và sau đó run_main_module.js được thực thi. Mã lõi như sau.

  1. yêu cầu('nội bộ/mô-đun/cjs/bộ tải').Module.runMain(process.argv[1]); 

Mã của Module.runMain như sau.

  1. chức năng executeUserEntryPoint(chính = process.argv[1]) { 
  2.   Mô-đun._load(chính, vô giá trịĐÚNG VẬY); 

Cuối cùng, việc tải và thực thi mã người dùng được hoàn thành thông qua _load. Dưới đây chúng tôi phân tích chi tiết các trình tải khác nhau.

2 Thực hiện tải mô-đun

Chúng tôi thường tải các mô-đun thông qua yêu cầu và yêu cầu xử lý mọi thứ cho chúng tôi. Trên thực tế, có rất nhiều loại mô-đun trong Node.js. Chúng tôi sẽ giới thiệu từng loại mô-đun bên dưới.

2.1 mô-đun JSON.

  1. Mô-đun._phần mở rộng['.json'] = chức năng(mô-đun, tên tệp) { 
  2.   const content = fs.readFileSync(tên tệp, 'utf8'); 
  3.  
  4.   thử { 
  5.     module.exports = JSONParse(stripBOM(content)); 
  6.   } bắt (err) { 
  7.     err.message = tên tệp + ': ' + lỗi.thông điệp; 
  8.     ném lỗi; 
  9.   } 
  10. }; 

Việc triển khai mô-đun JSON rất đơn giản, chỉ cần đọc nội dung của tệp và phân tích nó.

2.2 Mô-đun JS người dùng.

Hãy nói về cơ chế mô-đun của Node.js

Chúng ta hiểu tại sao chúng ta có thể sử dụng trực tiếp hàm require khi viết mã. Không phải vì require là biến toàn cục mà vì mã chúng ta viết sẽ được gói gọn trong một hàm để thực thi. của hàm, khi thực thi mã của chúng ta, Node.js sẽ truyền vào các tham số thực tế, vì vậy chúng ta có thể sử dụng các biến này. Hàm yêu cầu có thể tải JS do người dùng xác định hoặc JS gốc, chẳng hạn như mạng, nhưng trước tiên Node.js sẽ tìm kiếm JS gốc.

2.3 Mô-đun JS gốc.

Hãy nói về cơ chế mô-đun của Node.js

Nguyên tắc tải của mô-đun JS gốc và mô-đun JS người dùng tương tự nhau, nhưng có một số khác biệt. Chúng tôi thấy rằng khi thực thi mã mô-đun JS gốc, các tham số thực tế được truyền vào khác với các tham số khi tải JS người dùng. Đầu tiên, giá trị của biến yêu cầu là trình tải mô-đun JS gốc, do đó, chỉ các mô-đun JS gốc mới có thể được tải thông qua yêu cầu trong mô-đun JS gốc. Có một tham số thực tế khác cần được chú ý, đó là InternalBinding được sử dụng để tải các mô-đun C++, vì vậy các mô-đun C++ có thể được tải thông qua InternalBinding trong JS nguyên gốc.

2.4 mô-đun C++.

Hãy nói về cơ chế mô-đun của Node.js

2.5 Mô-đun bổ trợ

Hãy nói về cơ chế mô-đun của Node.js

Phần tái bút: Cơ chế mô-đun là một phần rất cơ bản và quan trọng trong bất kỳ ngôn ngữ nào. Với sự hiểu biết sâu sắc về nguyên tắc cơ chế mô-đun của Node.js, chúng tôi biết điều gì sẽ xảy ra khi đạt được yêu cầu nếu bạn quan tâm đến việc triển khai cụ thể. tải mô-đun, bạn có thể. Để đọc mã nguồn của Node.js, bạn cũng có thể xem kho lưu trữ https://github.com/theanarkh/js_runtime_loader.

Liên kết gốc: https://mp.weixin.qq.com/s/v_0Mo_AJHJxXTcnzN2bAaw.

Cuối cùng, bài viết nói về cơ chế mô-đun của Node.js kết thúc tại đây. Nếu bạn muốn biết thêm về cách nói về cơ chế mô-đun của Node.js, vui lòng tìm kiếm bài viết CFSDN hoặc tiếp tục duyệt qua các bài viết liên quan. Hỗ trợ blog của tôi trong tương lai! .

32 4 0
qq735679552
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress