Node.JSオンデマンドでモジュールをダウンロードする

たとえば、大量のデータを処理する場合、最大の環境リソースを使用して作業に費やす合計時間を削減するために、異なるオブジェクトに対して同様のタスクを同時に実行する競合プロセスを使用する必要があります。



npmの簡単なパッケージを開発しているとします。 たとえば、 storage



(storage)と名前を付けましょう。 FsStorage



(ファイルストレージ)、 MysqlStorage



(MySQLストレージ)、 MongoStorage



(Mongoストレージ)など、いくつかのタイプのストレージのいずれかを使用する可能性を予測します。



パッケージのソースコードの内容を配布します(ネタバレの下):



プロジェクトのソースコードの大まかなスケッチ
  • package.json







     { "name": "storage", "version": "0.1.0", "main": "./lib/index.js", "dependencies": { "mysql": "*", "mongoose": "*" } }
          
          



  • lib/index.js







     module.exports = { FsStorage: require('./fs-storage.jsx'), MysqlStorage: require('./mysql-storage.jsx'), MongoStorage: require('./mongo-storage.jsx') };
          
          



  • lib/fs-storage.js







     var fs = require('fs'); module.exports = FsStorage; function FsStorage() { // init code... }
          
          



  • lib/mysql-storage.js







     var mysql = require('mysql'); module.exports = MysqlStorage; function MysqlStorage() { // init code... }
          
          



  • lib/mongo-storage.js







     var mongoose = require('mongoose'); module.exports = MongoStorage; function MongoStorage() { // init code... }
          
          







直接的なmysql



およびmongoose



依存関係コードは、デモには必要ありません。 したがって、 mysql



およびmongoose



コードの代わりに、スタブを(スポイラーの下に)配置します。



Mysqlおよびmongooseスタブソースコード
  • node_modules/mysql/index.js





     console.log('MySQL module loaded');
          
          



  • node_modules/mongoose/index.js





     console.log('Mongoose module loaded');
          
          





パッケージのファイル構造は次のようになります(ネタバレの下):



ファイル構造ツリーのレイアウト
 storage/ ├ lib/ │ ├ index.js │ ├ fs-storage.js │ ├ mongo-storage.js │ └ mysql-storage.js ├ node_modules/ │ ├ mongoose/ │ │ └ index.js │ └ mysql/ │ └ index.js └ package.json
      
      





ここで、いくつかの子プロセスを使用して実行する非常に大きなタスクがあり、その完了時にファイル形式のストレージを使用する必要があると想像してください。



 var storage = require('storage'); var fsStorage = new storage.FsStorage();
      
      





開始して観察します。各子プロセスは、予想よりも1桁多くのメモリを占有します。 競合するプロセスの数が100を超える場合、これがリアルタイムでサーバー上で実行される唯一のタスクではありません。



ここでは、たとえば、ファイルストレージを使用する場合、 MySQLデータベース管理ライブラリとMongo ODMクライアントの両方をダウンロードする必要がないことを理解しています。



require('storage')



呼び出した直後に、メッセージがコンソールに表示されます:



 MySQL module loaded Mongoose module loaded
      
      





Object.defineProperty()



メソッドObject.defineProperty()



実験して、私はdemandProperty()



関数として設計した驚くべき結果を達成しました。



 function demandProperty(obj, name, modPath) { Object.defineProperty(obj, name, { configurable: true, enumerable: true, get: function() { var mod = require(modPath); Object.defineProperty(obj, name, { configurable: false, enumerable: true, value: mod }); return mod } }) }
      
      





操作の原理は単純です。たとえば、 MysqlStorage()



への直接リンクの代わりに、アクセサー( getter )が作成されます。 アクセサーへの要求では、 require()



トリガーされ、アクセサー自体がrequire()



結果を返します。 さらに、同じObject.defineProperty()



を使用して、アクセサではなくrequire()



同じ結果(つまりMysqlStorage()



)への直接リンクを設定し直しました。 したがって、すべてのリクエスト(もちろん、最初のリクエストを除く)は、従来のrequire()



をそのままにしているかのように、リークからの同じ速度と信頼性で動作します。



lib/index.js



変更しlib/index.js



。 交換:



 module.exports = { FsStorage: require('./fs-storage.jsx'), MysqlStorage: require('./mysql-storage.jsx'), MongoStorage: require('./mongo-storage.jsx'), };
      
      



に:



 demandProperty(module.exports, 'FsStorage', './fs-storage.jsx'); demandProperty(module.exports, 'MysqlStorage', './mysql-storage.jsx'); demandProperty(module.exports, 'MongoStorage', './mongo-storage.jsx');
      
      





そして使用:



 var storage = require('storage'); console.log(util.inspect(storage)); /* => { FsStorage: [Getter], MysqlStorage: [Getter], MongoStorage: [Getter] } */ console.log(util.inspect(storage.FsStorage.name)); // => 'FsStorage' console.log(util.inspect(storage)); /* => { FsStorage: [Function: FsStorage], MysqlStorage: [Getter], MongoStorage: [Getter] } */ var mysql = new storage.MysqlStorage(); // => MySQL module loaded console.log(util.inspect(mysql)); // => '{}' console.log(util.inspect(storage)); /* => { FsStorage: [Function: FsStorage], MysqlStorage: [Function: MysqlStorage], MongoStorage: [Getter] } */
      
      





別の微妙な点があります。 demandProperty()



関数の定義がlib



フォルダー内のモジュールの外部で取得される場合、最後の引数はモジュールへのフルパスでなければなりません。



 demandProperty(module.exports, 'FsStorage', path.resolve(__dirname, './fs-storage.jsx')); demandProperty(module.exports, 'MysqlStorage', path.resolve(__dirname, './mysql-storage.jsx')); demandProperty(module.exports, 'MongoStorage', path.resolve(__dirname, './mongo-storage.jsx'));
      
      







すべての成功した実験!



All Articles