node.jsのモジュールについて、動作を確認してみました。 こんな処にも、ノンブロッキングI/Oの実行モデルの影響があるんですね。 しっかり頭を切り替えて考えないと、バグを埋め込んでしまいます。
モジュールの関数をアクセスする
#!/usr/bin/env node
var app = require('./mod1a');
console.log("app.abc = ", app.abc(1, 2));
console.log("app.xyz = ", app.xyz(2, 3));
関数名をexportsするには、次の書き方になります。
exports.abc = function(a, b) {
return a + b;
};
exports.xyz = function(a, b) {
return a * b;
};
実行結果
$ ./test1a.js
app.abc = 3
app.xyz = 6
もう一つの書き方
読み難くなりますが、functionを省略して、スッキリ書くこともできます。
exports.abc = (a, b) => a + b;
exports.xyz = (a, b) => a * b;
コールの方法は同じです。
#!/usr/bin/env node
var app = require('./mod1b');
console.log("app = ", app.abc(1, 2));
console.log("app = ", app.xyz(2, 3));
もう一つの書き方の実行結果
$ ./test1b.js
app = 3
app = 6
さらにカッコを使った書き方
複数行の処理を書きたい場合は、{}カッコで括ることができます。
exports.abc = (a, b) => {
c = a + b;
return c;
}
exports.xyz = (a, b) => {
c = a * b;
return c;
}
モジュールのオブジェクトにアクセスする
変数を次の書き方で、エクスポートできます。
var x = 100;
module.exports = x;
#!/usr/bin/env node
var app = require('./mod2');
console.log("app = ", app);
実行結果
$ ./test2.js
app = 100
モジュールにモジュールを与えて実行する
前述のmod1をmod3に与えて実行するものです。
#!/usr/bin/env node
var app1 = require('./mod1');
var app3 = require('./mod3')(app1);
console.log("app = ", app3);
module.exports = function(app) {
return app.abc(3, 4);
};
実行結果
$ ./test3.js
app = 7
モジュールでメインを判別する
require.main === module が false であれば、モジュールとして呼び出されている事を表し、true であればモジュール自身が、ダイレクトに実行されている。
exports.abc = function(a, b) {
return a + b;
};
if (require.main === module) {
console.log("result = ", exports.abc(1, 2));
}
#!/usr/bin/env node
var app = require('./mod4');
console.log("app = ", app.abc(4, 5));
実行結果
次の前半が、ダイレクトに実行、後半がメインモジュールから実行されるケース
$ node mod4.js
main = true
result = 29
$ ./test4.js
main = false
app = 9
モジュールの多重取り込みのケース
mod7a.js のモジュールから、mod7b.js モジュールを読み込みます。
console.log('a starting');
exports.done = false;
const b = require('./mod7b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
一方、mod7b.js モジュールは、mod7a.jsモジュールを読み込みます。
console.log('b starting');
exports.done = false;
const a = require('./mod7a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
メインのモジュールからは、mod7a,mod7b を順番に取り込みます。
#!/usr/bin/env node
console.log('main starting');
const a = require('./mod7a.js');
const b = require('./mod7b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
実行結果
メッセージのmod7a の読み込みと実行を待たずに、mod7b が読み込まれ実行を開始して、mod7bの終了後に、mod7a が実行されています。おそらく、平行で動作していると考えても良いと思います。 モジュールを取り込む場合、逐次実行ではなく、平行実行である事に注意する必要がありますね。
$ ./test7.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true
参考資料
(1) Node.js v6.11.1 Documentation Modules https://nodejs.org/dist/latest-v6.x/docs/api/modules.html#modules_accessing_the_main_module