Rumah > Artikel > hujung hadapan web > Ketahui tentang modul fail dan modul teras dalam Node dalam satu artikel
Artikel ini akan membawa anda melalui modul fail dan modul teras dalam Nod, dan bercakap tentang pencarian modul fail, penyusunan dan pelaksanaan modul fail, serta penyusunan dan pelaksanaan JavaScript dan C /C modul teras Saya harap Bermanfaat untuk semua orang!
Apabila kami menggunakan Nodejs untuk pembangunan harian, kami sering menggunakan require untuk mengimport dua jenis modul, satu ialah modul yang kami tulis sendiri atau gunakan npm Modul pihak ketiga yang dipasang, modul jenis ini dipanggil 文件模块
dalam Node; jenis lain ialah modul terbina dalam Node yang disediakan untuk kami gunakan, seperti os
, fs
dan modul lain, modul ini dipanggil. 核心模块
.
Perlu diambil perhatian bahawa perbezaan antara modul fail dan modul teras bukan sahaja sama ada ia terbina dalam oleh Node, tetapi juga kedudukan fail, penyusunan dan proses pelaksanaan modul perbezaan antara keduanya. Bukan itu sahaja, modul fail juga boleh dibahagikan kepada modul fail biasa, modul tersuai atau modul sambungan C/C, dsb. Modul yang berbeza juga mempunyai banyak butiran yang berbeza dalam kedudukan fail, penyusunan dan proses lain.
Artikel ini akan menangani isu ini dan menjelaskan konsep modul fail dan modul teras serta proses dan butiran khusus mereka yang perlu diberi perhatian dalam lokasi fail, penyusunan atau pelaksanaan membantu anda.
Mari mulakan dengan modul fail.
Apakah modul fail?
Dalam Node, modul yang diperlukan menggunakan pengecam modul bermula dengan .、.. 或 /
(iaitu, menggunakan laluan relatif atau laluan mutlak) akan dianggap sebagai modul fail. Selain itu, terdapat jenis modul khas Walaupun ia tidak mengandungi laluan relatif atau laluan mutlak, dan ia bukan modul teras, ia menunjuk ke pakej Apabila Node mencari jenis modul ini, ia akan menggunakan 模块路径
untuk mencari modul satu persatu Modul jenis ini Dipanggil modul tersuai.
Oleh itu, modul fail termasuk dua jenis, satu modul fail biasa dengan laluan, dan satu lagi modul tersuai tanpa laluan.
Modul fail dimuatkan secara dinamik pada masa jalan, yang memerlukan proses penentududukan, penyusunan dan pelaksanaan fail yang lengkap serta lebih perlahan daripada modul teras.
Untuk kedudukan fail, Node mengendalikan kedua-dua jenis modul fail ini secara berbeza. Mari kita lihat dengan lebih dekat proses carian untuk kedua-dua jenis modul fail ini.
Untuk modul fail biasa, memandangkan laluan dibawa dan arahnya sangat jelas, carian tidak akan mengambil masa yang lama, jadi carian kecekapan adalah lebih tinggi daripada yang berikut Modul tersuai yang diperkenalkan adalah lebih tinggi sedikit. Walau bagaimanapun, masih terdapat dua perkara yang perlu diberi perhatian.
Pertama, dalam keadaan biasa, apabila menggunakan memerlukan untuk memperkenalkan modul fail, sambungan fail biasanya tidak ditentukan, seperti:
const math = require("math");
Memandangkan sambungan tidak ditentukan, Node tidak boleh namun menentukan dokumen akhir. Dalam kes ini, Node akan melengkapkan sambungan dalam susunan .js、.json、.node
dan mencubanya satu demi satu Proses ini dipanggil 文件扩展名分析
.
Satu lagi perkara yang perlu diberi perhatian ialah dalam pembangunan sebenar, selain memerlukan fail tertentu, kami biasanya juga menentukan direktori, seperti:
const axios = require("../network");
Dalam kes ini, Node akan terlebih dahulu lakukan analisis sambungan fail Jika fail yang sepadan tidak dijumpai, tetapi direktori diperoleh, Node akan menganggap direktori sebagai pakej.
Secara khusus, Node akan mengembalikan fail yang ditunjuk oleh medan package.json
main
dalam direktori sebagai hasil carian. Jika fail yang ditunjuk oleh utama adalah salah, atau fail package.json
tidak wujud sama sekali, Node akan menggunakan index
sebagai nama fail lalai, dan kemudian menggunakan .js
dan .node
dalam urutan untuk melaksanakan analisis sambungan dan cari fail sasaran satu persatu Jika tiada Jika dijumpai, ralat akan dilemparkan.
(Sudah tentu, memandangkan Node mempunyai dua jenis sistem modul, CJS dan ESM, selain mencari medan utama, Node juga akan menggunakan kaedah lain. Memandangkan ia berada di luar skop artikel ini, saya akan bukan pergi ke butiran.)
Seperti yang dinyatakan sebentar tadi, Node akan menggunakan laluan modul apabila mencari modul tersuai laluan?
Rakan yang biasa dengan penghuraian modul harus tahu bahawa laluan modul ialah tatasusunan yang terdiri daripada laluan Nilai khusus boleh dilihat dalam contoh berikut:
// example.js console.log(module.paths);
Hasil cetakan: <.>
Seperti yang anda lihat, modul dalam Node mempunyai tatasusunan laluan modul, yang disimpan dalam dan digunakan untuk menentukan cara Node mencari modul tersuai yang dirujuk oleh modul semasa. module.paths
具体来讲,Node 会遍历模块路径数组,逐个尝试其中的路径,查找该路径对应的 node_modules
目录中是否有指定的自定义模块,如果没有就向上逐级递归,一直到根目录下的 node_modules
目录,直到找到目标模块为止,如果找不到的话就会抛出错误。
可以看出,逐级向上递归查找 node_modules
目录是 Node 查找自定义模块的策略,而模块路径便是这个策略的具体实现。
同时我们也得出一个结论,在查找自定义模块时,层级越深,相应的查找耗时就会越多。因此相比于核心模块和普通的文件模块,自定义模块的加载速度是最慢的。
当然,根据模块路径查找到的仅仅是一个目录,并不是一个具体的文件,在查找到目录后,同样地,Node 会根据上文所描述的包处理流程进行查找,具体过程不再赘述了。
以上是普通文件模块和自定义模块的文件定位的流程和需要注意的细节,接下来我们来看者两类模块是如何编译执行的。
当定位到 require 所指向的文件后,通常模块标识符都不带有扩展名,根据上文提到的文件扩展名分析我们可以知道,Node 支持三种扩展名文件的编译执行:
JavaScript 文件。通过 fs
模块同步读取文件后编译执行。除了 .node
和 .json
文件,其他文件都会被当作 .js
文件载入。
.node
文件,这是用 C/C++ 编写后编译生成的扩展文件,Node 通过 process.dlopen()
方法加载该文件。
json 文件,通过 fs
模块同步读取文件后,使用 JSON.parse()
解析并返回结果。
在对文件模块进行编译执行之前,Node 会使用如下所示的模块封装器对其进行包装:
(function(exports, require, module, __filename, __dirname) { // 模块代码 });
可以看到,通过模块封装器,Node 将模块包装进函数作用域中,与其他作用域隔离,避免变量的命名冲突、污染全局作用域等问题,同时,通过传入 exports、require 参数,使该模块具备应有的导入与导出能力。这便是 Node 对模块的实现。
了解了模块封装器后,我们先来看 json 文件的编译执行流程。
json 文件的编译执行是最简单的。在通过 fs
模块同步读取 JSON 文件的内容后,Node 会使用 JSON.parse() 解析出 JavaScript 对象,然后将它赋给该模块的 exports 对象,最后再返回给引用它的模块,过程十分简单粗暴。
在使用模块包装器对 JavaScript 文件进行包装后,包装之后的代码会通过 vm
模块的 runInThisContext()
(类似 eval) 方法执行,返回一个 function 对象。
然后,将该 JavaScript 模块的 exports、require、module 等参数传递给这个 function 执行,执行之后,模块的 exports 属性被返回给调用方,这就是 JavaScript 文件的编译执行过程。
在讲解 C/C++ 扩展模块的编译执行之前,先介绍一下什么是 C/C++ 扩展模块。
C/C++ 扩展模块属于文件模块中的一类,顾名思义,这类模块由 C/C++ 编写,与 JavaScript 模块的区别在于其加载之后不需要编译,直接执行之后就可以被外部调用了,因此其加载速度比 JavaScript 模块略快。相比于用 JS 编写的文件模块,C/C++ 扩展模块明显更具有性能上的优势。对于 Node 核心模块中无法覆盖的功能或者有特定的性能需求,用户可以编写 C/C++ 扩展模块来达到目的。
那 .node
文件又是什么呢,它跟 C/C++ 扩展模块有什么关系?
事实上,编写好之后的 C/C++ 扩展模块经过编译之后就生成了 .node
文件。也就是说,作为模块的使用者,我们并不直接引入 C/C++ 扩展模块的源代码,而是引入 C/C++ 扩展模块经过编译之后的二进制文件。因此,.node
文件并不需要编译,Node 在查找到 .node
文件后,只需加载和执行该文件即可。在执行的过程中,模块的 exports 对象被填充,然后返回给调用者。
Perlu diperhatikan bahawa fail .node
yang dijana dengan menyusun modul sambungan C/C mempunyai bentuk yang berbeza di bawah platform yang berbeza: di bawah sistem *nix
, modul sambungan C/C disusun menjadi dinamik oleh penyusun seperti g/gcc Fail objek kongsi pautan mempunyai sambungan .so
; di bawah Windows
ia disusun ke dalam fail perpustakaan pautan dinamik oleh pengkompil Visual C dan mempunyai sambungan .dll
. Tetapi sambungan yang kami gunakan dalam penggunaan sebenar ialah .node
Sebenarnya, sambungan .node
hanyalah untuk kelihatan lebih semula jadi, sebenarnya, di bawah Windows
ia adalah fail .dll
, di bawah *nix
Di bawah adalah. fail .so
. Selepas
Node menemui fail .node
yang diperlukan, ia akan memanggil kaedah process.dlopen()
untuk memuatkan dan melaksanakan fail. Memandangkan fail .node
mempunyai bentuk fail yang berbeza di bawah platform yang berbeza, untuk mencapai pelaksanaan merentas platform, kaedah dlopen()
mempunyai pelaksanaan yang berbeza di bawah platform Windows
dan *nix
, dan kemudiannya dirangkumkan melalui libuv
lapisan keserasian. Rajah berikut menunjukkan proses menyusun dan memuatkan modul sambungan C/C di bawah platform yang berbeza:
Teras modul berada dalam Semasa proses penyusunan kod sumber Nod, fail boleh laku binari disusun. Apabila proses Node bermula, beberapa modul teras dimuatkan terus ke dalam memori Oleh itu, apabila modul teras ini diperkenalkan, dua langkah lokasi fail dan penyusunan dan pelaksanaan boleh diabaikan, dan akan dinilai sebelum modul fail dalam laluan. analisis. Jadi kelajuan pemuatannya adalah yang terpantas.
Modul teras sebenarnya dibahagikan kepada dua bahagian yang ditulis dalam C/C dan JavaScript Fail C/C disimpan dalam direktori src projek Node, dan fail JavaScript disimpan dalam direktori lib. Jelas sekali, proses penyusunan dan pelaksanaan kedua-dua bahagian modul ini adalah berbeza.
Untuk penyusunan modul teras JavaScript, semasa proses penyusunan kod sumber Node, Node akan menggunakan alat js2c.py yang disertakan dengan V8 , menukar semua kod JavaScript terbina dalam, termasuk modul teras JavaScript, kepada tatasusunan dalam C dan kod JavaScript disimpan dalam ruang nama nod dalam bentuk rentetan. Apabila memulakan proses Node, kod JavaScript dimuatkan terus ke dalam memori.
Apabila modul teras JavaScript diperkenalkan, Node akan memanggil process.binding()
untuk mencari lokasinya dalam ingatan melalui analisis pengecam modul dan mendapatkannya. Selepas dikeluarkan, modul teras JavaScript juga akan dibalut oleh pembungkus modul, kemudian dilaksanakan, objek eksport akan dieksport dan dikembalikan kepada pemanggil.
Dalam modul teras, beberapa modul semuanya ditulis dalam C/C, dan beberapa modul mempunyai bahagian teras yang lengkap oleh C/C , bahagian lain dibalut atau dieksport oleh JavaScript untuk memenuhi keperluan prestasi Modul seperti buffer
, fs
dan os
semuanya ditulis dalam C/C. Modul C ini melengkapkan teras di dalam badan utama, dan modul JavaScript melaksanakan enkapsulasi di luar badan utama ialah cara biasa untuk Node meningkatkan prestasi.
Bahagian modul teras yang ditulis dalam C/C tulen dipanggil modul terbina dalam, seperti node_fs
, node_os
, dll. Ia biasanya tidak dipanggil secara langsung oleh pengguna, tetapi bergantung secara langsung pada modul teras JavaScript. Oleh itu, semasa pengenalan modul teras Node, terdapat rantai rujukan sedemikian:
Jadi bagaimanakah modul teras JavaScript memuatkan modul terbina dalam?
Ingat kaedah process.binding()
? Node mengalih keluar modul teras JavaScript daripada memori dengan memanggil kaedah ini. Kaedah ini juga berfungsi dengan modul teras JavaScript untuk membantu memuatkan modul terbina dalam.
Khusus untuk pelaksanaan kaedah ini, apabila memuatkan modul terbina dalam, mula-mula buat objek eksport kosong, kemudian panggil kaedah get_builtin_module()
untuk mengeluarkan objek modul terbina dalam, isi objek eksport dengan melaksanakan register_func()
, dan akhirnya mengembalikannya kepada Pemanggil menyelesaikan eksport. Ini ialah proses pemuatan dan pelaksanaan modul terbina dalam.
Melalui analisis di atas, untuk pengenalan rantai rujukan seperti modul teras, mengambil modul os sebagai contoh, proses umum adalah seperti berikut:
Ringkasnya, pengenalan Proses modul os melibatkan pengenalan modul fail JavaScript, pemuatan dan pelaksanaan modul teras JavaScript, dan pemuatan dan pelaksanaan modul terbina dalam Proses ini sangat rumit dan rumit , tetapi untuk pemanggil modul, kerana pelaksanaan kompleks asas dan butiran dilindungi, Keseluruhan modul boleh diimport hanya melalui require(), yang sangat mudah. mesra.
Artikel ini memperkenalkan konsep asas modul fail dan modul teras serta proses dan butiran khusus mereka yang perlu diberi perhatian dalam lokasi fail, penyusunan atau pelaksanaan . Khususnya:
Modul fail boleh dibahagikan kepada modul fail biasa dan modul tersuai berdasarkan proses kedudukan fail. Modul fail biasa boleh ditempatkan secara langsung kerana laluannya yang jelas, kadangkala melibatkan proses analisis sambungan fail dan analisis direktori modul tersuai akan mencari berdasarkan laluan modul, dan selepas carian berjaya, lokasi fail akhir akan dilakukan melalui analisis direktori .
Modul fail boleh dibahagikan kepada modul JavaScript dan modul sambungan C/C mengikut proses penyusunan dan pelaksanaan yang berbeza. Selepas modul JavaScript dibalut oleh pembungkus modul, ia dilaksanakan melalui kaedah vm
modul runInThisContext
memandangkan modul sambungan C/C sudah menjadi fail boleh laku yang dijana selepas penyusunan, ia boleh dilaksanakan secara langsung dan objek yang dieksport dikembalikan kepada pemanggil.
Modul teras dibahagikan kepada modul teras JavaScript dan modul terbina dalam. Modul teras JavaScript dimuatkan ke dalam memori apabila proses Node dimulakan dan kemudian dilaksanakan melalui kaedah process.binding()
kompilasi dan pelaksanaan modul terbina dalam akan diproses oleh process.binding()
, get_builtin_module()
dan register_func()
fungsi .
Selain itu, kami juga mendapat rantai rujukan untuk Node untuk memperkenalkan modul teras, iaitu modul fail-->modul teras JavaScript-->modul terbina dalam , dan juga pelajari Modul C melengkapkan teras secara dalaman, dan modul JavaScript melaksanakan kaedah penulisan modul merangkum secara luaran.
Untuk lebih banyak pengetahuan berkaitan pengaturcaraan, sila lawati: Video Pengaturcaraan! !
Atas ialah kandungan terperinci Ketahui tentang modul fail dan modul teras dalam Node dalam satu artikel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!