ホームページ  >  記事  >  ウェブフロントエンド  >  Node のファイル モジュールとコア モジュールについて 1 つの記事で学習します

Node のファイル モジュールとコア モジュールについて 1 つの記事で学習します

青灯夜游
青灯夜游転載
2022-07-18 20:05:402229ブラウズ

この記事では、Node のファイル モジュールとコア モジュールについて説明し、ファイル モジュールの検索、ファイル モジュールのコンパイルと実行、JavaScript と C のコンパイルと実行について説明します。 /C コア モジュール。皆さんのお役に立てれば幸いです。

Node のファイル モジュールとコア モジュールについて 1 つの記事で学習します

日常の開発で Nodejs を使用する場合、よく require を使用して 2 種類のモジュールをインポートします。1 つは自分で作成するモジュール、または npm を使用するモジュールです。インストールされたサードパーティ モジュール。このタイプのモジュールは Node では file module と呼ばれます。もう 1 つのタイプは、os、# など、Node が使用するために Node によって提供される組み込みモジュールです。 ## fs およびその他のモジュール。これらのモジュールは コア モジュール と呼ばれます。

ファイル モジュールとコア モジュールの違いは、ノードに組み込まれているかどうかだけでなく、ファイルの配置、モジュールのコンパイル、実行プロセスにもあることに注意してください。両者の明らかな違いは次のとおりです。それだけでなく、ファイル モジュールは通常のファイル モジュール、カスタム モジュール、C/C 拡張モジュールなどに細分化することもできます。モジュールが異なれば、ファイルの配置、コンパイル、その他のプロセスにおいても多くの詳細が異なります。

この記事では、これらの問題に対処し、ファイル モジュールとコア モジュールの概念、およびファイルの場所、コンパイル、または実行で注意する必要がある特定のプロセスと詳細を明確にします。あなたに役立ちます。

ファイルモジュールから始めましょう。

ファイル モジュール

ファイル モジュールとは何ですか?

Node では、

.、..、または / で始まるモジュール識別子を使用する (つまり、相対パスまたは絶対パスを使用する) 必要なモジュールは、ファイル モジュールとして扱われます。さらに、特別なタイプのモジュールがあります。これには相対パスや絶対パスが含まれておらず、コア モジュールでもありませんが、パッケージを指します。Node がこのタイプのモジュールを見つけると、 # が使用されます。 ##Module Path を指定してモジュールを 1 つずつ検索します。このようなモジュールをカスタム モジュールと呼びます。 したがって、ファイル モジュールには、パスを持つ通常のファイル モジュールと、パスのないカスタム モジュールの 2 種類が含まれます。

ファイル モジュールは実行時に動的にロードされます。これには完全なファイルの配置、コンパイル、実行プロセスが必要で、コア モジュールよりも時間がかかります。

ファイルの配置に関して、Node はこれら 2 種類のファイル モジュールを異なる方法で処理します。これら 2 種類のファイル モジュールの検索プロセスを詳しく見てみましょう。

通常のファイル モジュールの検索

通常のファイル モジュールの場合、パスが運ばれ、方向が非常に明確であるため、検索にそれほど時間はかかりません。導入したカスタムモジュールは少し高めです。ただし、まだ注意すべき点が 2 つあります。

まず、通常の状況では、require を使用してファイル モジュールを導入する場合、通常、ファイル拡張子は指定されません。例:

const math = require("math");

拡張子が指定されていないため、ノードはまだ判断できません。最後のファイル。この場合、Node は

.js、.json、.node

の順に拡張子を完成させ、1 つずつ試します。このプロセスを ファイル拡張子解析 と呼びます。 もう 1 つ注意すべき点は、実際の開発では、特定のファイルが必要であることに加えて、通常は次のようなディレクトリも指定することです。

const axios = require("../network");

この場合、ノードは最初にファイルを実行します。対応するファイルが見つからなくても、ディレクトリが取得された場合、Node はそのディレクトリをパッケージとして扱います。

具体的には、Node はディレクトリ内の

package.json

main フィールドが指すファイルを検索結果として返します。 main によって指定されたファイルが間違っている場合、または package.json ファイルがまったく存在しない場合、Node はデフォルトのファイル名として index を使用し、その後 を使用します。 js, .node 拡張子解析を行い、対象ファイルを1つずつ検索し、見つからない場合はエラーとなります。 (もちろん、Node には CJS と ESM という 2 種類のモジュール システムがあるため、メイン フィールドの検索に加えて、他のメソッドも使用します。この記事の範囲外なので、詳細は説明しません。)

カスタム モジュールの検索

先ほど述べたように、Node はカスタム モジュールを検索するときにモジュール パスを使用します。パス?

モジュール解析に詳しい人は、モジュール パスがパスで構成される配列であることを知っているはずです。具体的な値は次の例で確認できます:

// example.js
console.log(module.paths);

結果の出力:

Node のファイル モジュールとコア モジュールについて 1 つの記事で学習しますご覧のとおり、Node のモジュールにはモジュール パス配列があり、これは

module.paths

に保存され、Node がカスタム ファイルを検索する方法を指定するために使用されます。現在のモジュールによって参照されるモジュール。 <p>具体来讲,Node 会遍历模块路径数组,逐个尝试其中的路径,查找该路径对应的 <code>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 文件的编译执行

json 文件的编译执行是最简单的。在通过 fs 模块同步读取 JSON 文件的内容后,Node 会使用 JSON.parse() 解析出 JavaScript 对象,然后将它赋给该模块的 exports 对象,最后再返回给引用它的模块,过程十分简单粗暴。

JavaScript 文件的编译执行

在使用模块包装器对 JavaScript 文件进行包装后,包装之后的代码会通过 vm 模块的 runInThisContext()(类似 eval) 方法执行,返回一个 function 对象。

然后,将该 JavaScript 模块的 exports、require、module 等参数传递给这个 function 执行,执行之后,模块的 exports 属性被返回给调用方,这就是 JavaScript 文件的编译执行过程。

C/C++ 扩展模块的编译执行

在讲解 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 对象被填充,然后返回给调用者。

C/C 拡張モジュールをコンパイルして生成される .node ファイルは、プラットフォームごとに異なる形式になることに注意してください。 *nix システムの C/C 拡張モジュールこれは、g/gcc などのコンパイラによって、拡張子 .so が付いたダイナミック リンク共有オブジェクト ファイルにコンパイルされます。Windows では、 Visual C コンパイラ。拡張子は .dll です。ただし、実際に使用する拡張子は .node です。実際、.node の拡張子は、より自然に見えるようにするためのものです。実際、## の Windows では、## の下にあります。 # これは .dll ファイルであり、*nix の下では .so ファイルです。

Node は必要な

.node ファイルを見つけた後、process.dlopen() メソッドを呼び出してファイルをロードして実行します。 .node ファイルはプラットフォームごとにファイル形式が異なるため、クロスプラットフォームを実現するために、Windows と ## では dlopen() メソッドが使用されます。 #*nix プラットフォームの下にはさまざまな実装があり、それらは libuv 互換性レイヤーを通じてカプセル化されます。次の図は、さまざまなプラットフォームでの C/C 拡張モジュールのコンパイルとロードのプロセスを示しています。

Node のファイル モジュールとコア モジュールについて 1 つの記事で学習します

コア モジュール

コアmodule is Node ソース コードのコンパイル プロセス中に、バイナリ実行可能ファイルがコンパイルされます。 Node プロセスの開始時に、一部のコア モジュールがメモリに直接ロードされるため、これらのコア モジュールを導入すると、ファイルの場所とコンパイルと実行の 2 つの手順が省略され、パス内のファイル モジュールより前に判定されます。そのため、読み込み速度が最も速くなります。

コア モジュールは実際には C/C と JavaScript で記述された 2 つの部分に分かれており、C/C ファイルは Node プロジェクトの src ディレクトリに格納され、JavaScript ファイルは lib ディレクトリに格納されます。明らかに、モジュールのこれら 2 つの部分のコンパイルおよび実行プロセスは異なります。

JavaScript コア モジュールのコンパイルと実行

JavaScript コア モジュールのコンパイルでは、Node ソース コードのコンパイル プロセス中に、Node は js2c.py ツールを使用します。これは V8 に付属しており、JavaScript コア モジュールを含むすべての組み込み JavaScript コードを C の配列に変換し、JavaScript コードは文字列の形式でノードの名前空間に保存されます。 Node プロセスを開始すると、JavaScript コードがメモリに直接ロードされます。

JavaScript コア モジュールが導入されると、Node は

process.binding() を呼び出します。

モジュール識別子の解析によってメモリ内の位置を特定し、取り出します。 JavaScript コア モジュールも取り出された後、モジュール ラッパーによってラップされてから実行され、exports オブジェクトがエクスポートされて呼び出し元に返されます。

C/C コア モジュールのコンパイルと実行

コア モジュールでは、すべて C/C で記述されているモジュールもあれば、C/C でコア部分を完成しているモジュールもあります。 C/C 、他の部分はパフォーマンス要件を満たすために JavaScript によってパッケージ化またはエクスポートされます。

buffer

fsos などのモジュールはすべて C/ を通じて部分的に実装されます。 C で書かれています。この C モジュールはメイン部分の内側にコアを実装し、JavaScript モジュールはメイン部分の外側にカプセル化を実装しますこれは、Node のパフォーマンスを向上させる一般的な方法です。 純粋な C/C で書かれたコア モジュールの部分は、node_fs

node_os などの組み込みモジュールと呼ばれます。通常は呼び出されません。ユーザーによって直接実行されますが、JavaScript コア モジュールに直接依存します。したがって、Node のコア モジュールの導入中に、次のような参照チェーンが存在します。

それでは、JavaScript コア モジュールはどのようにして組み込みモジュールをロードするのでしょうか? Node のファイル モジュールとコア モジュールについて 1 つの記事で学習します

process.binding()

メソッドを覚えていますか? ノードは、このメソッドを呼び出すことによって、メモリから JavaScript コア モジュールを削除します。このメソッドは JavaScript コア モジュールでも動作し、組み込みモジュールのロードを支援します。

このメソッドの実装に特有の、組み込みモジュールをロードするときは、最初に空のエクスポート オブジェクトを作成し、次に get_builtin_module()

メソッドを呼び出して組み込みモジュールを取り出します。 module オブジェクトを取得し、

register_func () を実行します。エクスポート オブジェクトを入力し、最後に呼び出し元に返してエクスポートを完了します。組み込みモジュールのロードと実行のプロセスです。 上記の分析を通じて、os モジュールを例としてコア モジュールなどのリファレンス チェーンを導入する場合の一般的なプロセスは次のとおりです。

#要約すると、OS モジュールのプロセスには、JavaScript ファイル モジュールの導入、JavaScript コア モジュールの読み込みと実行、組み込みモジュールの読み込みと実行が含まれます。このプロセスは非常に面倒で複雑です。ただし、モジュールの呼び出し側にとっては、基礎となる複雑な実装と詳細がシールドされているため、モジュール全体は、非常に単純な require() を介して簡単にインポートできます。フレンドリー。

概要

この記事では、ファイル モジュールとコア モジュールの基本概念と、ファイルの場所、コンパイル、実行で注意する必要がある特定のプロセスと詳細について紹介します。 。具体的には:

  • ファイル モジュールは、さまざまなファイル配置プロセスに従って、通常のファイル モジュールとカスタム モジュールに分けることができます。通常のファイル モジュールはパスが明確であるため、直接見つけることができますが、ファイル拡張子分析やディレクトリ分析のプロセスが必要になる場合があります。カスタム モジュールはモジュール パスに基づいて検索され、検索が成功した後、最終的なファイルの場所はディレクトリ分析によって実行されます。 。

  • ファイル モジュールは、さまざまなコンパイルおよび実行プロセスに従って、JavaScript モジュールと C/C 拡張モジュールに分類できます。 JavaScript モジュールがモジュール ラッパーによってパッケージ化された後、vm モジュールの runInThisContext メソッドを通じて実行されます。C/C 拡張モジュールはすでに実行されているため、直接実行できます。コンパイル後に生成される実行可能ファイル。 は、エクスポートされたオブジェクトを呼び出し元に返します。

  • #コア モジュールは、JavaScript コア モジュールと組み込みモジュールに分かれています。 JavaScript コア モジュールは、Node プロセスの開始時にメモリにロードされます。これを取り出して、

    process.binding() メソッドを通じて実行できます。組み込みモジュールのコンパイルと実行が行われます。 process.binding()get_builtin_module()、および register_func() の処理。

さらに、コア モジュール、つまりファイル モジュール -> JavaScript コア モジュール -> 組み込みモジュールを導入するための Node のリファレンス チェーンも取得しました。

C モジュールは内部的に実装されてコアを完成させ、JavaScript モジュールは外部的に実装されて モジュールの記述メソッドをカプセル化します。

プログラミング関連の知識について詳しくは、

プログラミング ビデオをご覧ください。 !

以上がNode のファイル モジュールとコア モジュールについて 1 つの記事で学習しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。