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

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

Mar 08, 2019 pm 05:34 PM
javascriptnode.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 サイトの他の関連記事を参照してください。

声明
この記事はsegmentfaultで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへ:すべてがどのように機能するかC/CからJavaScriptへ:すべてがどのように機能するかApr 14, 2025 am 12:05 AM

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

JavaScriptエンジン:実装の比較JavaScriptエンジン:実装の比較Apr 13, 2025 am 12:05 AM

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

ブラウザを超えて:現実世界のJavaScriptブラウザを超えて:現実世界のJavaScriptApr 12, 2025 am 12:06 AM

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)Apr 11, 2025 am 08:23 AM

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)Apr 11, 2025 am 08:22 AM

この記事では、許可によって保護されたバックエンドとのフロントエンド統合を示し、next.jsを使用して機能的なedtech SaaSアプリケーションを構築します。 FrontEndはユーザーのアクセス許可を取得してUIの可視性を制御し、APIリクエストがロールベースに付着することを保証します

JavaScript:Web言語の汎用性の調査JavaScript:Web言語の汎用性の調査Apr 11, 2025 am 12:01 AM

JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。

See all articles

ホット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衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

SublimeText3 中国語版

SublimeText3 中国語版

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

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。