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'));
すべての成功した実験!