我正在创建一个依赖于另一个异步的模块。我试图找到公开我的模块的最佳方式,以便使用它的开发人员发现它很直观。
最初我的模块看起来像这样:
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 返回到可接受的场景吗?或者我应该在模块初始化时返回一个回调函数,让开发人员处理剩下的工作?
答案 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();