创建一个具有异步构造函数的对象数组

时间:2014-12-16 13:34:11

标签: javascript node.js object asynchronous callback

我想用NodeJS执行以下操作。创建以下对象数组,其中每个对象在初始化时都有不同的局部变量。

obj.js

var Obj = function (_id) {
    this.id = _id;
    var that=this;
    db.getData(_id,function(collection){ //this method is asynchronous 

        collection.toArray(function(err, items) {
            that.data=items;
        });
    });
}

Obj.prototype.data = [];  

module.exports = Obj;

app.js

var arr=[];
arr.push(new obj(24));
arr.push(new obj(41));
arr.push(new obj(24));
arr.push(new obj(42));
//then do tasks with the arr

但是由于arr构造函数是同步的,因此当我使用arr进行计算时,它们可能无法获取所有数据。那么如何处理这种情况呢?我想确保在使用它们之前成功创建了所有对象。

提前致谢。

2 个答案:

答案 0 :(得分:2)

小伙子,@ mscdex说的是对的。 首先,在您的代码中,data将在内存中共享,您应该在构造函数中使用this.data=[]。 其次,正如@mscdex所说,将你的方法转移到原型中,比如说

Obj.prototype.load=function(){
    //code here...
}

然后你的代码如下:

var Obj = function(_id){
    this.id=_id;
    this.data = [];
}
Obj.prototype.load = function(){
    var that = this;
    db.getData(this.id,function(collection){ //this method is asynchronous
        collection.toArray(function(err, items) {
            that.data=items;
        });
    });
    return that;
}

最后,你的问题,你怎么知道所有这些都准备好了。

Obj.prototype.ready = [];
Obj.prototype.loaded=function(){
    this.ready.push(1);
    if(this.ready.length == Obj.target)
        Obj.onComplete();
}
Obj.notifyme = function(callback,len){
    Obj.target = len;
    Obj.onComplete = callback;
}

上面的代码设置了一个数组来计算加载完成实例(使用数组,因为无法从实例' s __proto__引用中读取基本值)。所以你应该做的是将这个事件(函数)添加到load,所以代码最后可能如下:

Obj.prototype.load = function(){
    var that = this;
    db.getData(this.id,function(collection){ //this method is asynchronous
        collection.toArray(function(err, items) {
            that.data=items;
            that.loaded();
        });
    });
    return that;
}
var args = [24,41,42];
Obj.notifyme(function(){/*then do tasks with the arr*/},args.length);
var arr = args.map(function(arg){
    return new Obj(arg).load();
});

告诉函数notifyme回调工作和实例数。最后一个问题是,如果您执行此例程多次,则应重置targetcallback,因为它们是Obj全局事物。

答案 1 :(得分:1)

我会使用Promise模式。这是这种方法的原型。我使用本机浏览器Promise进行实现和测试。对于NodeJS,您可以将Kowal的Q实现与类似(或非常接近)的API一起使用。

var Obj = function (_id) {
    this.id = _id;
    var that = this;

    this.promise = function() {
        return new Promise(function(resolve) {
            db.getData(_id, function (collection) {
                collection.toArray(function (err, items) {
                    that.data.push(items);
                    resolve(that);
                });
            });
        });
    }();
};

Obj.prototype.data = [];


function objFactory(args) {
    var promises = args.map(function(el) {
        return new Obj(el).promise;
    });
    return Promise.all(promises);
}

objFactory([24, 25, 41, 42]).then(function(arr) {
    console.log(arr, arr[0].data);
});

这个想法是,当objFactory返回的promise对象解析时,它将调用相应的then回调,在其中使用data是可靠的,因为它已经被填充了时间。

这是我正在测试代码的浏览器demo。您必须为NodeJS环境采用它。但这个想法仍然是一样的。

例如,使用Kris Kowal的Q,它将是这样的:

this.promise = function() {
    var deferred = Q.defer();
    db.getData(_id, function (collection) {
        collection.toArray(function (err, items) {
            that.data.push(items);
            deferred.resolve(that);
        });
    });
    return deferred.promise;
}();

Q.all代替Promise.all