Node.jsでコールバック関数を書く

## 最もシンプルな例
StackOverflowから引用
http://stackoverflow.com/questions/2190850/create-a-custom-callback-in-javascript

```js:simple.js
function doSomething(callback) {
    // Call the callback
    callback('stuff', 'goes', 'here');
}
function foo(a, b, c) {
    // I'm the callback
    console.log(a + " " + b + " " + c);
}
doSomething(foo);
```

実行するとdoSomething >> fooの順番に処理が行われます。
しかし、これを多段にすると

```js:multi_callbacks.js
var log = '';
function step1(callback) {
    log += 'step1 ';
    callback();
}
function step2(callback) {
    log += 'step2 ';
    callback();
}
function step3(callback) {
    log += 'step3 ';
    callback();
}
function step4(callback) {
    log += 'step4 ';
    callback();
}
step1(function(){
    step2(function(){
        step3(function(){
            step4(function(){
                console.log('log:', log); //log: step1 step2 step3 step4
                console.log('done');
            })
        })
    })
});
```

あっという間にコールバック地獄となります。

## コールバックのnestを回避する
コードがネストし過ぎて辛いので、コールバックの仕組みを作ります。

```js:emitter.js
// Perfect JavaScriptより
var str = '';
var emitter = {
    callbacks: [], //コールバック関数の置き場
    register: function(fn) { // コールバック関数を登録する
        this.callbacks.push(fn);
    },
    onOpen: function() { //発火装置
        this.callbacks.forEach(function(f) {
            f();
        });
    }
};

// emitterを使ってみる
emitter.register(function() {
    str += "Sunday ";
});
emitter.register(function() {
    str += "Monday ";
});
emitter.register(function() {
    str += "Tuesday ";
});
emitter.onOpen();
// 結果確認
console.log(str); //Sunday Monday Tuesday
```

### コールバック関数に、クロージャを利用する
クロージャを利用することで、コールバック関数に状態を持たせることができます。
[>> クロージャの記事も書きました！](http://qiita.com/HitsujixTweet/items/8a0966f44eefc0dc6ac9)

```js:callback_closure.js
// クロージャを登録する
var emitter = {
    callbacks: [],
    register: function(fn) {
        this.callbacks.push(fn);
    },
    onOpen: function() {
        this.callbacks.forEach(function(f) {
            f();
        });
    }
};

// 即時関数を使ったクロージャを登録する
emitter.register(function() {
    var name = 'dog';
    return (function() {
        console.log(name+' is called!');
    }());
});
emitter.register(function() {
    var name = 'cat';
    return (function() {
        console.log(name+' is called!');
    })();
});
emitter.onOpen();
```

実際はemitterのような仕組みを自力で作るのは大変なので、npmパッケージを利用したりします。
その一例ですが >> [Promise-Qの使い方](http://qiita.com/HitsujixTweet/items/cc9b731f4abe1e5bc45a)


## ２つのファイル間でコールバックする
まずはお題のサンプルを作ります。

```js:family_simple.js
var my_family = {
    members:[],
    add_member: function(m){
        this.members.push(m);
    },
    show_members: function() {
        var members = this.members;
        setTimeout(function(){
            members.forEach(function(m){
                console.log(m);
            });
        }, 500);
    }
};
my_family.add_member('hoge'); //hogeをpush
my_family.add_member('fuga'); //fugaをpush
my_family.show_members(); //membersを順に表示する
```

この処理を２つのファイルに分けて、コールバックさせるよう書いてみます。

```js:family.js
module.exports = {
    members : [],
    add_member: function(name) {
        this.members.push(name);
    },
    get_members: function(callback) {
        var members = this.members;
        setTimeout(function(){
            callback(members);
        }, 500);
    }
};
```

```js:family_manager.js
var my_family = require('./family');
my_family.add_member('hoge');
my_family.add_member('fuga');

var callback = function(members){
    members.forEach(function(name){
        console.log(name);
    });
};
my_family.get_members(callback);
```

このようにrequireとmodule.exportsを使って、異なるファイル間でcallbackのやり取りができます。
ただ、この例だとfamily.jsのmembersに直接参照できてしまうので、それを避けたい場合は次のような書き方もできます。

```js:family2.js
module.exports = (function(){
    var members = [];
    function add_member(name) {
        members.push(name);
    }
    function get_members(callback) {
        setTimeout(function(){
            callback(members);
        }, 500);
    }
    return {
        add_member: add_member,
        get_members: get_members
    };
}());
```

```js:family_manager2.js
var my_family = require('./family2');
my_family.add_member('hoge');
my_family.add_member('fuga');

var callback = function(members){
    members.forEach(function(name){
        console.log(name);
    });
};
my_family.get_members(callback);
```