Node対Common JSのモジュール仕様


Nodeは比較的程度の姿で現れることができます。Common JS規格の影響と切り離せません。NodeはCommon JSのModules規範を参考にして、非常に使いやすいモジュールシステムを実現しました。NPMはpackages規範に対する完全なサポートによって、Nodeが開発過程で応用するのは効果的です。
Nodeでモジュールを参照するには、次の3つのステップが必要です。
1.経路分析
Nodeのモジュールはコアモジュールとファイルモジュールに分けられます。
コアモジュールはNodeによって提供されるモジュールです。Nodeソースコードのコンパイル中にバイナリ実行ファイルにコンパイルされました。Nodeプロセスが起動すると、コアモジュールは直接メモリにロードされます。したがって、コアモジュールを参照する時、ファイルの位置付けとコンパイルはこの二つのステップを省略し、パス分析で優先的に判断します。だから、そのロード速度は一番速いです。requireでコアモジュールを参照する場合は、そのまま参照すればいいです。如き  require('http')ファイルモジュールはユーザーが作成したモジュールで、動作時に動的にロードされるので、完全なパス分析、ファイルの位置付け、コンパイル実行のプロセスが必要です。だから、その速度はコアモジュールより遅いです。参照ファイルモジュールの方式は3つに分けられます。
1.で始まる相対パスファイルモジュール。
2.絶対パスファイルモジュールを/で開始します。
3.パス形式以外のファイルモジュール(カスタムモジュール)。
1,2つの方法は、ユーザーが自分で作成したモジュールを参照するために使用され、requireは経路を真実の経路に変え、実際の経路をインデックスとしてコンパイルして実行した結果(オブジェクト)をキャッシュに保存します。特定のファイル位置を指定したので、そのロード速度はコアモジュールより遅く、カスタムモジュールよりも速いです。第3の方法では、ダウンロードされたサードパーティモジュールを参照するのに最も時間がかかります。ここに一つあります モジュールパスの概念。カスタムモジュールの検索速度が遅いのはこのためです。

/**
         ,               :      node_modules  ,     node_modules  ,         ,       node_modules  。
 */
 //a.js
 console.log(module.paths) 
 //        
 [ 'H:\\Files\\qiuzhao\\please-offer\
ode_modules', 'H:\\Files\\qiuzhao\
ode_modules', 'H:\\Files\
ode_modules', 'H:\
ode_modules' ]
1.require('./a.js')
2.require('/a.js')
3.require('koa')
2.ファイルの位置付け
1)ファイル拡張子:Common JS仕様は、識別子にファイル拡張子を含まないことができます。Nodeは.js,json,nodeの順に拡張子を補足して、順次試します。
2)カタログ分析とパッケージ(カスタムモジュール):requireに提供された識別子を分析する過程で、ファイル拡張子の順に試行した後も、対応するファイルが得られていませんでしたが、カタログが得られました。これはカスタムモジュールを参照してモジュールパスに沿って1つずつ検索するとよく現れます。この時、Nodeはディレクトリをパッケージとして処理します。この場合、Nodeはまず現在のディレクトリでpackage.json(パッケージ記述ファイル)を検索し、JSON.parse()によりオブジェクトを解析した後、メール属性で指定されたファイル名を取り出して位置を特定し、場合によってはj拡張子の分析を行う。main属性で指定されたファイル名が間違っていたり、package.jsonファイルがまったくない場合は、Nodeはindexをデフォルトのファイル名として、拡張子の順に試します。ディレクトリ解析中にどのファイルにも位置決めできなかった場合は、モジュールパスの次のパスを検索します。モジュールパス配列が遍歴済みでファイルが見つからなかったら、エラーを投げます。
3.コンパイル実行
Nodeでは、各ファイルはモジュールであり、各モジュールはオブジェクトであり、このオブジェクトの定義は以下の通りである。

function Module(id,parent){
    this.id = id
    this.exports = {}
    this.parent = parent
    if(parent&&parent.children){
      parent.push(this)
    }
    this.filename = null
    this.loaded = false
    this.children = []  //                 
  }

ファイルの位置決めに成功したら、まずNodeができます。 新しいオブジェクトを作成し、ファイルの内容を読み込み、編集して実行します。 モジュールのexport属性を呼び出し元に戻します。異なる拡張子のファイルには、異なるロード方法があり、 require.extensions を通じてシステムおよびサポートされているファイルのロード方法を見ることができる。
1).jsファイル:fsモジュール経由 ファイルの読み込みを同期してコンパイルします。
このタイプのファイルをコンパイルすると、Nodeは取得したファイルの内容を最後まで包装し、ヘッダに追加します。 (function(exports、require、module、_ufilenamedirname){、テールに追加 }) 。正常なjsファイルは次のように包装されます。

(function(exports,require,module,__dirname,__filename){
   ... 
  })  //       ,node      ,      js                      ,         ,  node       。
包装後のコードはvm原生モジュールのrun InThisContext()方法によって実行されます。具体的なfunctionオブジェクト(run InThisContext()の役割はここで宣言されます。最後に、現在のモジュールオブジェクト(Nodeがファイルに成功したことを忘れないようにしてください。まずmoduleオブジェクトを作成します。)のexporte属性は、extreメソッドです。module自体と、前の2ステップで得られた完全なファイルパスとファイルディレクトリをパラメータとしてこの関数に渡す。ここにはちょっと古典的な例があります。

//                    
  
  //error
  exports = {}
  
  
  //right
  module.exports = {}
  
  //       ,exports modlue.exports         , exports={}    ,    module.exports     。Node          module.exports

var val = 10
  var chageVal = function(val){
    val = 100
    console.log(val)
  }
  changeVal(val) //100
  console.log(val) //
  
  /----------------------/
  
  var obj = {
    age:12
  }
  
  var changeName = function(obj){
    obj = {
      age:21
    }
    console.log(obj.age)
  }
  
  changeName(obj) //21
  console.log(obj.age) //12
  
  //          ,      ,         。

2)nodeファイル:これはC/C++を使って作成した拡張ファイルで、最後にコンパイルした結果をdleopen()メソッドでロードします。dleopen()方法は異なるプラットフォームで異なる実装を行い,libuv互換層によりカプセル化した。実際には,nodeのモジュールファイルはコンパイルする必要がないので,C/C++モジュールを作成してコンパイルして生成したのです。ここではロードと実行のプロセスだけがあり,コンパイルのプロセスがありません。実行中、モジュールのexportオブジェクトは.nodeモジュールと連絡を取り、その後にコーディネーターに戻る。
3)jsonファイル:fsモジュールでファイルを同期して読み込んだら、JSON.parse()で解析して結果を返します。このタイプのファイルは三つの中で最も簡単にコンパイルされ、Nodeはfsモジュールでファイルの内容を同期して読み込むと、JSON.parse()を呼び出してオブジェクトに解析し、モジュールオブジェクトのexportに値を割り当て、外部呼び出しを行う。
4)他の拡張子ファイル:jsファイルとして処理されます。
モジュールのキャッシュ
フロントエンドブラウザが静止スクリプトファイルをキャッシュして性能を向上させたのと同じように、Nodeが参照モジュールをキャッシュして、二次導入時のオーバヘッドを低減します。違いは、ブラウザがキャッシュしているのはファイルであり、Nodeキャッシュしているのはコンパイルと実行後のオブジェクトです。require()方法は同じモジュールの二次ローディングに対して、キャッシュ優先方式を採用しています。これは第一優先順位です。各コンパイルが成功したモジュールはそのファイルパスをインデックスとして保存します。cache対象にModule._cacheはrequire()メソッドのcache属性に値を与えられますので、require.cacheによってキャッシュされたモジュールも確認できます。キャッシュされたモジュールを使用したくない場合は、参照されたモジュールに追加できます。 delete require.cache[module.filename]です。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。