Reputation: 53
I want to do the following with NodeJS. Make an object array of the following, where each object has different local variables where they want to get when they initialize.
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
But since the arr constructor is synchronous they may not have get all the data when I do calculations with the arr. So how to handle this scenario ? I want to make sure that all the objects are successfully created before doing any work with them.
Thanks in advance.
Upvotes: 2
Views: 80
Reputation: 349
guy, what @mscdex said is correct.
Firstly, in your code, data
will be shared in memory, you should use this.data=[]
in constructor.
Secondly, as @mscdex said, move your method into prototype, say
Obj.prototype.load=function(){
//code here...
}
then your code my like below:
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;
}
finally, your question, how do you know all of them are ready.
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;
}
the above code set an array to count load complete instances(use array because basic value could not be read from an instance's __proto__
reference). So what you should do is add this event(function) to load
, so the code at last may be as following:
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();
});
tell function notifyme
the callback work and the number of instances. The last problem is if you do this routine more than one times you should reset target
and callback
since they are Obj
global things.
Upvotes: 2
Reputation: 193291
I would make use of Promise pattern. Here is prototype of such an approach. I used native browser Promise for implementation and testing. In case of NodeJS you can use Kowal's Q implementation with similar (or very close) 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);
});
The idea is that when the promise object returned by objFactory
resolves it will invoke corresponding then
callback, inside of which it's reliable to work with data
since it's populated for sure by that time.
Here is browser demo I was testing code with. You will have to adopt it for NodeJS environment. But the idea remains the same.
For example using Kris Kowal's Q it will be something like this:
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;
}();
and Q.all
instead of Promise.all
.
Upvotes: 1