ホームページ ウェブフロントエンド jsチュートリアル Node でのモジュール実装プロセスの詳細な紹介 (例付き)

Node でのモジュール実装プロセスの詳細な紹介 (例付き)

Mar 08, 2019 pm 05:34 PM
javascript node.js モジュラー

この記事では、Node でのモジュール実装プロセスを詳しく紹介します (例を示します)。一定の参考価値があります。必要な友人は参照できます。お役に立てれば幸いです。

CommonJS はモジュールを定義し、エクスポートし、モジュールの仕様を要求します。この単純な標準を実装するために、Node.js は基盤となる C/C 組み込みモジュールから JavaScript コア モジュールまで、パス分析、ファイルの配置からコンパイルまでを行います。一連の複雑なプロセスを経ました。 Node モジュールの原理を簡単に理解すると、Node に基づくフレームワークを再理解するのに役立ちます。

1. CommonJS モジュールの仕様

CommonJS の仕様または標準は単なる理論であり、JavaScript にはクライアントの開発だけでなく、ホスト環境全体で実行できる機能が期待されています。アプリケーションは、サーバー アプリケーション、コマンド ライン ツール、デスクトップ グラフィカル インターフェイス アプリケーションなどを開発することもできます。

CommonJS 仕様は、モジュールを 3 つの部分で定義します:

モジュール定義

モジュール オブジェクトは、モジュール自体を表すためにモジュール内に存在します。モジュール コンテキストは、exports 属性を提供します。およびメソッド エクスポート メソッドは、エクスポート オブジェクトにマウントすることで定義できます。たとえば、次のようになります。

    // math.js
   exports.add = function(){ //...}
ログイン後にコピー

モジュール リファレンス

module は、外部モジュールの API を導入するための require() メソッドを提供します。現在のコンテキストに:

   var math = require('math')
ログイン後にコピー
モジュール識別

モジュール識別は、実際には require() メソッドに渡されるパラメータであり、キャメルケースに従って名前を付けた文字列またはファイル パスにすることができます。

Node.js は CommonJS 仕様、特に CommonJS の Modules 仕様の設計を利用してモジュール システムを実装します。同時に、NPM は CommonJS の Packages 仕様を実装します。モジュールとパッケージは Node アプリケーション開発の基礎を形成します。

2. Node モジュールのロード原理

上記のモジュール仕様は module、exports、require だけで非常に単純に見えますが、Node はどのように実装されるのでしょうか?

パス分析 (モジュールの完全パス)、ファイルの場所 (ファイル拡張子またはディレクトリ)、コンパイルと実行の 3 つの手順を実行する必要があります。

2.1 パス解析

Review require() はモジュールを導入するためのモジュール識別子をパラメータとして受け取り、ノードはこの識別子を元にパス解析を行います。異なる識別子は異なる分析方法を使用し、主に次のカテゴリに分類されます。

http、fs、path など、Node によって提供されるコア モジュール

コア モジュールは、Node がコンパイルされるときにコンパイルされます。ソースコードはコンパイルされます バイナリの実行可能ファイルとして保存され、ノードの起動時にメモリに直接ロードされます パス解析が優先されるため、ロード速度が非常に速く、その後のファイルの配置、コンパイル、実行は必要ありません。

カスタム http モジュールなど、コア モジュールと同じ名前のカスタム モジュールをロードする場合は、別の識別子を使用するか、代わりにパスを使用する必要があります。

パス、.、..相対パス モジュールおよび /絶対パス モジュールの形式のファイル モジュール

.、..、または / で始まる識別子はファイル モジュールとして扱われ、ノードrequire() 内のパスはインデックスとして実際のパスに変換され、コンパイルされて実行されます。

ファイルモジュールはファイルの場所を明確にするため、パス解析時間は短縮されますが、ロード速度はコアモジュールより遅いだけです。

カスタム モジュール、つまり非パス形式のファイル モジュール

コア モジュールでも、パス形式のファイル モジュールでもありません。カスタム ファイルは特殊なファイル モジュールです。パスの場合、モジュール パス内のノード パスが一度に 1 レベルずつ検索されます。
モジュール パス検索戦略の例は次のとおりです。

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

// Terminal
$ node paths.js
[ '/Users/tong/WebstormProjects/testNode/node_modules',
'/Users/tong/WebstormProjects/node_modules',
'/Users/tong/node_modules',
'/Users/node_modules',
'/node_modules' ]
ログイン後にコピー

上記の例のモジュール パス配列出力からわかるように、モジュールを検索する場合、node_modules ディレクトリは、 JS プロトタイプ チェーンまたはスコープ チェーンと同様に、ターゲット パスに到達するまで現在のパスを保持します。パスが深くなるほど速度が遅くなるため、カスタム モジュールの読み込みが最も遅くなります。

キャッシュ優先メカニズム: ノードはインポートされたモジュールをキャッシュしてパフォーマンスを向上させます。ファイルをキャッシュするブラウザとは異なり、ノードはコンパイルおよび実行されたオブジェクトをキャッシュするため、require() は同じモジュールをキャッシュします。二次ロードではキャッシュ優先メソッドが採用されます。このキャッシュ優先度は第 1 優先度であり、コア モジュールの優先度よりも高くなります。

2.2 ファイルの配置

モジュール パスの分析が完了すると、主にファイル拡張子の分析、ディレクトリおよびパッケージの処理を含むファイルの配置が完了します。より明確に表現するために、ファイルの配置を 4 つのステップに分けます:

step1: 拡張子を補足する

通常、require() 内の識別子にはファイル拡張子は含まれません。 , Nodeは.js、.json、.nodeの順に拡張子を補完しようとします。

拡張子を追加しようとすると、fs モジュールを呼び出して同期的にブロックし、ファイルが存在するかどうかを確認する必要があります。そのため、ここでのパフォーマンスを向上させるちょっとしたトリックは、.json と .json を渡すときに拡張子を取り込むことです。ノードファイルを require() に追加すると、一部の速度が向上します。

step2: ディレクトリの処理と検索 pakage.json

拡張機能を追加した後に対応するファイルが見つからず、ディレクトリが取得された場合、Node はそのディレクトリをパッケージとして扱います。 CommonJS パッケージ仕様の実装に従って、Node はディレクトリ内で pakage.json (パッケージ説明ファイル) を検索し、JSON.parse() を通じてそれをパッケージ説明オブジェクトに解析し、main 属性で指定されたファイル名を取得します。 。

ステップ 3: デフォルトでインデックス ファイルの検索を続行します

如果没有pakage.json或者main属性指定的文件名错误,那 Node 会将 index 当做默认文件名,依次查找 index.js、index.json、index.node

step4: 进入下一个模块路径

在上述目录分析过程中没有成功定位时,自定义模块按路径查找策略进入上一层node_modules目录,当整个模块路径数组遍历完毕后没有定位到文件,则会抛出查找失败异常。

缓存加载的优化策略使得二次引入不需要路径分析、文件定位、编译执行这些过程,而且核心模块也不需要文件定位的过程,这大大提高了再次加载模块时的效率

2.3 编译执行

Node 中每个模块都是一个对象,在具体定位到文件后,Node 会新建该模块对象,然后根据路径载入并编译。不同的文件扩展名载入方法为:

.js 文件: 通过 fs 模块同步读取后编译执行.json 文件: 通过 fs 模块同步读取后,用JSON.parse()解析并返回结果.node 文件: 这是用 C/C++ 写的扩展文件,通过process.dlopen()方法加载最后编译生成的其他扩展名: 都被当做 js 文件载入

载入成功后 Node 会调用具体的编译方式将文件执行后返回给调用者。对于 .json 文件的编译最简单,JSON.parse()解析得到对象后直接赋值给模块对象的exports,而 .node 文件是C/C++编译生成的,Node 直接调用process.dlopen()载入执行就可以,下面重点介绍 .js 文件的编译:

在 CommonJS 模块规范中有module、exports 和 require 这3个变量,在 Node API 文档中每个模块还有 __filename、__dirname这两个变量,但是在模块中没有定义这些变量,那它们是怎么产生的呢?

事实上在编译过程中,Node 对每个 JS 文件都被进行了封装,例如一个 JS 文件会被封装成如下:

(function (exports, require, module, __filename, __dirname) {
    var math = require('math')
    export.add = function(){ //... }
})
ログイン後にコピー

首先每个模块文件之间都进行了作用域隔离,通过vm原生模块的runInThisContext()方法(类似 eval)返回一个具体的 function 对象,最后将当前模块对象的exports属性、require()方法、模块对象本身module、文件定位时得到的完整路径__filename和文件目录__dirname作为参数传递给这个 function 执行。模块的exports属性上的任何方法和属性都可以被外部调用,其余的则不可被调用。

至此,module、exports 和 require的流程就介绍完了。

曾经困惑过,每个模块都可以使用exports的情况下,为什么还必须用module.exports。

这是因为exports在编译过程中时通过形参传入的,直接给exports形参赋值只改变形参的引用,不能改变作用域外的值,例如:

let change = function (exports) {
  exports = 100
  console.log(exports)
}

var exports = 2
change(exports) // 100
console.log(exports) // 2
ログイン後にコピー

所以直接赋值给module.exports对象就不会改变形参的引用了。

编译成功的模块会将文件路径作为索引缓存在 Module._cache 对象上,路径分析时优先查找缓存,提高二次引入的性能。

三、Node 核心模块

总结来说 Node 模块分为Node提供的核心模块和用户编写的文件模块。文件模块是在运行时动态加载,包括了上述完整的路径分析、文件定位、编译执行这些过程,核心模块在Node源码编译成可执行文件时存为二进制文件,直接加载在内存中,所以不用文件定位和编译执行。

核心模块分为 C/C++ 编写的和 JavaScript 编写的两部分,在编译所有 C/C++ 文件之前,编译程序需要将所有的 JavaScript 核心模块编译为 C/C++ 可执行代码,编译成功的则放在 NativeModule._cache对象上,显然和文件模块 Module._cache的缓存位置不同。

在核心模块中,有些模块由纯 C/C++ 编写的内建模块,主要提供 API 给 JavaScript 核心模块,通常不能被用户直接调用,而有些模块由  C/C++ 完成核心部分,而 JavaScript 实现封装和向外导出,如 buffer、fs、os 等。

所以在Node的模块类型中存在依赖层级关系:内建模块(C/C++)—> 核心模块(JavaScript)—> 文件模块。

使用require()十分的方便,但从 JavaScript 到 C/C++ 的过程十分复杂,总结来说需要经历 C/C++ 层面内建模块的定义、(JavaScript)核心模块的定义和引入以及(JavaScript)文件模块的引入。

四、前端模块规范

对比前后端的 JavaScript,浏览器端的 JavaScript 需要经历从同一个服务器端分发到多个客户端执行,通过网络加载代码,瓶颈在于宽带;而服务器端 JavaScript 相同代码需要多次执行,通过磁盘加载,瓶颈在于 CPU 和内存,所以前后端的 JavaScript 在 Http 两端的职责完全不用。

Node 模块的引入几乎是同步的,而前端模块如果同步引入,那脚本加载需要太长的时间,所以 CommonJS 为后端 JavaScript 制定的规范不适合前端。而后出现 AMD 和 CMD 用于前端应用场景。

4.1 AMD 规范

AMD 即异步模块定义(Asynchronous Module Definition),模块定义为:

define(id?, dependencies?, factory);
ログイン後にコピー

AMD 模块需要用define明确定义一个模块,其中模块id与依赖dependencies是可选的,factory的内容就是实际代码的内容。例如指定一些依赖到模块中:

define(['dep1', 'dep2'], function(){
    // module code
});
ログイン後にコピー

require.js 实现 AMD 规范的模块化,感兴趣的可以查看 require.js 的文档。

4.2 CMD 规范

CMD 模块的定义更加简单:

 define(factory);
ログイン後にコピー

定义的模块同 Node 模块一样是隐式包装,在依赖部分支持动态引入,例如:

 define(function(require, exports, module){
     // module code
 });
ログイン後にコピー

requireexportsmodule通过形参传递给模块,需要依赖模块时直接使用require()引入。

sea.js 实现 AMD 规范的模块化,感兴趣的可以查看 sea.js 的文档。

以上がNode でのモジュール実装プロセスの詳細な紹介 (例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 Dec 17, 2023 am 08:41 AM

JavaScript は Web 開発で広く使用されているプログラミング言語であり、WebSocket はリアルタイム通信に使用されるネットワーク プロトコルです。 2 つの強力な機能を組み合わせることで、効率的なリアルタイム画像処理システムを構築できます。この記事では、JavaScript と WebSocket を使用してこのシステムを実装する方法と、具体的なコード例を紹介します。まず、リアルタイム画像処理システムの要件と目標を明確にする必要があります。リアルタイムの画像データを収集できるカメラ デバイスがあるとします。

JavaScript で HTTP ステータス コードを簡単に取得する方法 JavaScript で HTTP ステータス コードを簡単に取得する方法 Jan 05, 2024 pm 01:37 PM

JavaScript で HTTP ステータス コードを取得する方法の紹介: フロントエンド開発では、バックエンド インターフェイスとの対話を処理する必要があることが多く、HTTP ステータス コードはその非常に重要な部分です。 HTTP ステータス コードを理解して取得すると、インターフェイスから返されたデータをより適切に処理できるようになります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法と、具体的なコード例を紹介します。 1. HTTP ステータス コードとは何ですか? HTTP ステータス コードとは、ブラウザがサーバーへのリクエストを開始したときに、サービスが

See all articles