ホームページ  >  記事  >  ウェブフロントエンド  >  Node.js で require() メソッドがどのように動作するかを調べる

Node.js で require() メソッドがどのように動作するかを調べる

一个新手
一个新手オリジナル
2017-09-07 13:36:531174ブラウズ

ほぼすべての Node.js 開発者は、require() 関数が何をするのかを説明できますが、それがどのように機能するかを実際に知っている人はどれだけいるでしょうか?私たちはライブラリやモジュールをロードするために毎日これを使用していますが、その動作は私たちにとって謎です。

好奇心から、内部で何が起こっているのかを知るためにノードのコアコードを調べてみました。しかし、これは単一の関数ではありません。node のモジュール システムで module.js を見つけました。このファイルには、各ファイルのロード、コンパイル、キャッシュを制御する、驚くほど強力だが比較的馴染みのないコア モジュールが含まれています。 require() の出現は氷山の一角にすぎません。

module.jsfunction Module(id, parent) {
  this.id = id;
  this.exports = {};
  this.parent = parent;
  // ...

Module.js は Node.js 内で主に 2 つの役割を果たします。まず、すべての Node.js モジュールの基盤を提供します。各ファイルは、ファイルの実行後も存続する基本モジュールの新しいインスタンスです。そのため、module.exports に属性を添付し、必要に応じてそれらを返すことができます。

このモジュールの 2 番目の主要なタスクは、ノードのモジュール読み込みメカニズムを処理することです。私たちが使用する独立した操作「require」関数は、実際には module.require の抽象概念であり、それ自体は Module._load 関数の単純なカプセル化にすぎません。このロード メソッドは各ファイルの実際のロードを処理し、そこから作業を開始します。

Module._load

Module._load = function(request, parent, isMain) {
  // 1. Check Module._cache for the cached module. 
  // 2. Create a new Module instance if cache is empty.
  // 3. Save it to the cache.
  // 4. Call module.load() with your the given filename.
  //    This will call module.compile() after reading the file contents.
  // 5. If there was an error loading/parsing the file, 
  //    delete the bad module from the cache
  // 6. return module.exports
};

Module._load は、新しいモジュールのロードとモジュール キャッシュの管理を担当します。ロードされた各モジュールをキャッシュすると、冗長なファイル読み取りの数が減り、アプリケーションの速度が大幅に向上します。さらに、共有モジュール インスタンスにより、モジュールのシングルトン機能をプロジェクトの状態に維持できます。

モジュールがキャッシュに存在しない場合、Module._load はそのファイルの新しいベース モジュールを作成します。次に、新しいファイルの内容を module._compile に送信する前に読み取るようにモジュールに指示します。 [1]

上記のステップ #6 に気付いた場合は、 module.exports がユーザーに返されていることがわかります。これが、使用するパブリック インターフェイスを定義するときに、exports と module.exports を使用する理由です。これは、次に Module._load が必要なコンテンツを返すためです。これ以上の機能がないことに驚いていますが、あれば便利です。

module._compile

Module.prototype._compile = function(content, filename) {  // 1. Create the standalone require function that calls module.require.  // 2. Attach other helper methods to require.  // 3. Wraps the JS code in a function that provides our require,  //    module, etc. variables locally to the module scope.  // 4. Run that function};

ここで本当の魔法が起こります。まず、このモジュール用に特別なスタンドアロンの require 関数が作成されます。これは私たち全員が必要とする、よく知られた機能です。関数自体は Module.require の単なるラッパーであり、簡単に使用できるいくつかのあまり知られていない補助メソッドも含まれています:

· require(): 外部モジュールをロードします
· require.resolve():solveモジュール名をその絶対パスに変換します
· require.main: メインモジュール
· require.cache: キャッシュされたすべてのモジュール
· require.extensions: 拡張子に応じて有効なファイルタイプごとに使用できるコンパイルメソッド
1 回require の準備が完了すると、ロードされたソース コード全体が、require、module、exports、およびその他すべての公開変数をパラメータとして受け入れることができる新しい関数にカプセル化されます。これは、Node.js 環境との競合を防ぐためにモジュールをカプセル化するためだけに作成された関数です。

(function (exports, require, module, __filename, __dirname) {
  // YOUR CODE INJECTED HERE!
});

Module._compile メソッドは同期的に実行されるため、Module._load への呼び出しは、このコードの終わりまで待機することしかできず、ユーザーに module.exprts を返します。

結論

ということで、require のコード全体を確認し、それがどのように機能するかを暫定的に理解しました。

これをすべて実行した場合は、最後のシークレットである require('module') を使用する準備ができています。そうです、モジュール システム自体はモジュール システムを通じてロードできます。インセプション。奇妙に聞こえるかもしれませんが、これにより、Node.js コアを深く掘り下げることなく、ユーザー空間がモジュール読み込みシステムと対話できるようになります。一般的なモジュールはこのように構築されます。 [2]

さらに詳しく知りたい場合は、module.js のソースコードをご自身で確認してください。しばらく頭が痛くなるようなことがたくさんあります。 NODE_MODULE_CONTEXTS とは何か、そしてそれが追加された理由を最初に教えてくれた人にはボーナス ポイントが与えられます :)

[1] module._compile メソッドは、JavaScript ファイルを実行するためにのみ使用されます。JSON ファイルは、JSON.parse( を介して解析する必要があります。 ) を返し、

[2] を返します。ただし、どちらのモジュールも Module._resolveLookupPaths や Module._findPath などのプライベート モジュール メソッドに基づいて構築されています。これはそれほど優れたものではないと考えることもできます...

几乎所有的Node.js开发人员可以告诉你require()函数做什么,但我们又有多少人真正知道它是如何工作的?我们每天都使用它来加载库和模块,但它的行为,对于我们来说反而是一个谜。

出于好奇,我钻研了node的核心代码来找出在引擎下发生了什么事。但这并不是一个单一的功能,我在node的模块系统的找到了module.js。该文件包含一个令人惊讶的强大的且相对陌生的核心模块,控制每个文件的加载,编译和缓存。require() 它的横空出世,只是冰山的一角。

module.jsfunction Module(id, parent) {
  this.id = id;
  this.exports = {};
  this.parent = parent;
  // ...

在module.js在Node.js内部主要承担两个角色。首先,它为所有的Node.js模块提供了一个基础。每个文件是基本模块new出的一个新实例,即使在该文件已经运行之后,仍然存在。这就是为什么我们能够性为module.exports附加属并在需要时返回它们。

该模块的第二大任务是处理node的模块加载机制。我们使用的独立操作的“require”函数实际上是一个抽象概念的module.require,这本身就是只是一个简单的关于Module._load功能的封装。此load方法处理每个文件的实际加载,并在那里开始我们的旅程。

Module._load

Module._load = function(request, parent, isMain) {
  // 1. Check Module._cache for the cached module. 
  // 2. Create a new Module instance if cache is empty.
  // 3. Save it to the cache.
  // 4. Call module.load() with your the given filename.
  //    This will call module.compile() after reading the file contents.
  // 5. If there was an error loading/parsing the file, 
  //    delete the bad module from the cache
  // 6. return module.exports
};

Module._load负责加载新的模块和管理模块的缓存。缓存加载的每个模块减少冗余文件的读取次数,并可以显著地加快您应用程序的速度。此外,共享模块实例允许单例特性的模块,保持在项目中的状态。

如果某个模块没有在缓存中存在,Module._load将创建该文件的一个新的基本模块。然后,它会告诉模块在将它们发送到module._compile之前阅读新文件的内容。[1]

如果您注意到上面的步骤#6,你会看到module.exports已被返回给用户。这就是为什么当你在定义公共接口使用时,你使用exports和module.exports,因为Module._load将接下来返回require的内容。我很惊讶,这里没有更多的功能,但如果有的话那更好。

module._compile

Module.prototype._compile = function(content, filename) {  // 1. Create the standalone require function that calls module.require.  // 2. Attach other helper methods to require.  // 3. Wraps the JS code in a function that provides our require,  //    module, etc. variables locally to the module scope.  // 4. Run that function};

这是真正的奇迹发生的地方。首先,一个特殊的独立操作的require函数是为该模块创建的。这是我们需要的并且都熟悉的功能。而函数本身只是一个在Module.require的封装,它也包含了一些便于我们使用的鲜为人知的辅助方法:

· require():加载一个外部模块  
· require.resolve():解析一个模块名到它的绝对路径  
· require.main:主模块  
· require.cache:所有缓存好的模块
· require.extensions:根据其扩展名,对于每个有效的文件类型可使用的编制方法
一旦require准备好了,整个加载的源代码就会被封装在一个新的函数里,可以接受require,module,exports和所有其他暴露的变量作为参数。这是一个仅仅为封装模块的而创建的函数,以便于在防止与Node.js的环境产生冲突。

(function (exports, require, module, __filename, __dirname) {
  // YOUR CODE INJECTED HERE!
});

该Module._compile方法是同步执行的,所以对Module._load的调用只能等到这段代码运行结束,并将module.exprts返回给用户。

结论

因此,我们已经了解了require的全部代码,并已经初步了解它是如何工作的。

如果你已经按照这一切的方式做了,那么你已经为最后的秘密做好准备:require(‘module’)。这是正确的,该模块系统本身可以通过模块系统被加载。盗梦空间。这可能听起来很奇怪,但它可以让用户空间同模块加载系统互动起来,并不需要钻研Node.js核心。受欢迎的模块都像这样被建立。[2]

如果您想了解更多,请自己查看module.js源代码。还有很多东西足够你头痛一段时间了。第一个可以告诉我什么是NODE_MODULE_CONTEXTS“以及它为什么被添加的人可以得到加分奖励 :)

[1] module._compile方法只用于运行JavaScript文件。 JSON文件需通过JSON.parse() 解析并返回

[2]然而,这两个模块都建立在私有模块的方法,如Module._resolveLookupPaths和Module._findPath。你可以认为这并没有好多了…

以上がNode.js で require() メソッドがどのように動作するかを調べるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。