initializer.js 2.1 KB
/**
 * 依赖模块
 */
var debug = require('debug')('bootable');


/**
 * 创建一个初始化实例
 *
 * @constructor
 * @api public
 */
function Initializer() {
    this._phases = [];
}

/**
 * 运行所有的启动项
 *
 * 在运行初始化方法时, 所有的启动项将会按照注册顺序执行, 当所有启动项执行完毕
 * 回调用方法才会被执行
 *
 * @param {Function} cb
 * @param {Object} [thisArg]
 * @api public
 */
Initializer.prototype.run = function (cb, thisArg) {
    var phases = this._phases
        , idx = 0;

    function next(err) {
        if (err) { return cb(err); }

        var phase = phases[idx++];
        // 所有启动项执行完毕
        if (!phase) { return cb(); }

        try {
            if (typeof phase == 'object') {
                debug('%s', phase.constructor ? phase.constructor.name + '#boot' : 'anonymous#boot');
                phase.boot(next);
            } else {
                debug('%s', phase.name || 'anonymous');
                var arity = phase.length;
                if (arity == 1) {
                    phase.call(thisArg, next);
                } else {
                    phase.call(thisArg);
                    next();
                }
            }
        } catch (ex) {
            next(ex);
        }
    }
    next();
};

/**
 * 注册一个启动项
 *
 * 一个启动项可以是同步也可以是异步的. 同步启动项如下面的片段
 *
 *     function myPhase() {
 *       // perform initialization
 *     }
 *
 * 异步启动项像下面这样定义
 *
 *     function myAsyncPhase(done) {
 *       // perform initialization
 *       done();  // or done(err);
 *     }
 *
 * 启动项也可以是一个有boot function的对象,在这样的例子中,对象上的boot function会在启动序列
 * 执行的时候被调用。这种方式通常被应用在持久链接。例如数据库或是消息队列。
 *
 * @param {Function|Object} fn
 * @returns {Initializer} `this`, for a fluent interface.
 * @api public
 */
Initializer.prototype.phase = function (fn) {
    this._phases.push(fn);
    return this;
};


/**
 * 曝露初始化对象
 */
module.exports = Initializer;