nodejs异步模块初始化代码

时间:2015-04-07 11:08:59

标签: javascript node.js

我正在创建一个依赖于另一个异步的模块。我试图找到公开我的模块的最佳方式,以便使用它的开发人员发现它很直观。

最初我的模块看起来像这样:

var soap = require('soap');

var service = {};
soap.createClient('http://mysoapservice', function(err, client){
    service.myMethod = function(obj, callback){
        //dependency on soap module
        client.soapMethod(obj, function(err, data){
            //do something with the response
            //call other methods etc...
            var res = "processed "+data['name'];
            callback(err, res);
        });
    };
});
module.exports = service;

当然这里的问题是在达到模块代码内部回调之前调用 mymethod 会引发异常。

这种模块使用的最佳模式是什么?

将特定于其他库(q)的 promises 返回到可接受的场景吗?或者我应该在模块初始化时返回一个回调函数,让开发人员处理剩下的工作?

2 个答案:

答案 0 :(得分:1)

首先,我不会使用单身模式。如果用户想要多个服务怎么办?为此建立一个构造函数或工厂会更好。这提供了更多的设计灵活性,并使用户更清楚。例如:

// constructor
var Service = function() {
     this.initialized = false; // service is not initialized
};

Service.prototype.myMethod = function(...) {
     // check if initialized
     if (!this.initialized)
          return false;
     // do your stuff here
     ...
};

Service.prototype.initialize = function(..., cb) {
     // do your initialization and call the callback
     // also, set this.initialized to true
};

// want to have a factory, to provide a "createService" function?
// no problem
Service.createService = function(..., cb) {
     var service = new Service();
     service.initialize(..., cb);
     // service will only be usable once initialized, but the user
     // can still store a reference to the created object to use
     // in his callback
     return service;
};

module.exports = Service;

像这样使用:

// constructor + initializer
var myService = new Service();
service.initialize(..., function(...) {
    // we have the service, do stuff:
    myService.myMethod(...);
});

// factory method
var myService = Service.createService(..., function(...) {
    // we have the service, do stuff
    myService.myMethod(...);
});

在这两种情况下,在init之前调用myMethod()只会返回false(而不是抛出)。

我喜欢这种模式,因为它与流行模块的其他模式非常相似,因此用户习惯了它并知道会发生什么。

答案 1 :(得分:0)

我最终做的就是这个。仍不确定这是否是最佳实践,但符合我的需求。这样,如果在初始化结束之前调用该方法,则该函数将排队等待。

/**
 * An async module
 * @module asyncModule
 */
 var q = require('q');
 var debug = require('debug')('asyncModule');

 var service = (function () {
    //private
    var obj;
    var init_defer = q.defer();

    //constructor
    var service = function () {
        var self = this;
        //initialize async module
        setTimeout(function(){
            obj = {};
            obj._method = function(message, callback){
                callback(message+" altered");
            };

            //resolve defer
            init_defer.resolve(obj);
        }, 5000);
    };

    service.prototype.myMethod = function (message, callback) {
        var self = this;
        //queue function
        init_defer.promise.then(function(obj){
            debug(self.name);
            obj._method(message, function(msg){
                callback(null, msg);
            });
        });
    };

    service.prototype.configure = function(options){
        this.name = options.name;
    };

    return service;
})();

module.exports = new service();