Edited at

Node.js モジュール分割についてのメモ

More than 1 year has passed since last update.

node.jsのモジュールについて、動作を確認してみました。 こんな処にも、ノンブロッキングI/Oの実行モデルの影響があるんですね。 しっかり頭を切り替えて考えないと、バグを埋め込んでしまいます。


モジュールの関数をアクセスする


test1a.js

#!/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するには、次の書き方になります。


mod1a.js

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を省略して、スッキリ書くこともできます。


mod1b.js

exports.abc = (a, b) => a + b;

exports.xyz = (a, b) => a * b;

コールの方法は同じです。


test1b.js

#!/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


さらにカッコを使った書き方

複数行の処理を書きたい場合は、{}カッコで括ることができます。


mod1c.js

exports.abc = (a, b) => {

c = a + b;
return c;
}
exports.xyz = (a, b) => {
c = a * b;
return c;
}


モジュールのオブジェクトにアクセスする

変数を次の書き方で、エクスポートできます。


mod2.js

var x = 100;

module.exports = x;


test2.js

#!/usr/bin/env node


var app = require('./mod2');
console.log("app = ", app);


実行結果

$ ./test2.js

app = 100


モジュールにモジュールを与えて実行する

前述のmod1をmod3に与えて実行するものです。


test3.js

#!/usr/bin/env node


var app1 = require('./mod1');
var app3 = require('./mod3')(app1);

console.log("app = ", app3);



mod3.js

module.exports = function(app) {

return app.abc(3, 4);
};


実行結果

$ ./test3.js 

app = 7


モジュールでメインを判別する

require.main === module が false であれば、モジュールとして呼び出されている事を表し、true であればモジュール自身が、ダイレクトに実行されている。


mod4.js

exports.abc = function(a, b) {

return a + b;
};

if (require.main === module) {
console.log("result = ", exports.abc(1, 2));
}



test4.js

#!/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 モジュールを読み込みます。


mod7a.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モジュールを読み込みます。


mod7b.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 を順番に取り込みます。


test7.js

#!/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