Reputation: 11
I am new to the world of node.js and Javascript and I have a loop that goes over an array of objects at a certain condition I need to call a function that does asnyc work and the loop to stop while the function isn't done
fucntion foo1(arr){
for(var i=0 ; arr.length>i ; i++){
if(i==8){//or any other condition
doAsyncStuff(hits[i])
}
}
}
function doAsyncStuff(item){
parser.parseURL(someurl,function(error,result){
item.someprop=result.someprop;
})
}
the problem is no matter what I do, I can't seem to make the function wait it end's before I have the result and doesn't update the item I need it to update. I understand it's a common issue but none of the solution I found worked. any help would be welcome. Thanks!
Upvotes: 0
Views: 342
Reputation: 23472
If I understand you correctly then you could use a Promise
chain, serialised using reduce
(a for
loop would also work), something like this
function doAsyncStuff(item) {
return new Promise(resolve => {
const time = Math.ceil(Math.random() * 2000 + 1000);
window.setTimeout(() => {
item.someprop = time;
resolve();
}, time);
});
}
function foo1(arr) {
return arr.reduce(
(promise, item, index) => index % 2 === 0 ? promise.then(() => doAsyncStuff(item)) : promise,
Promise.resolve()
);
}
const hits = new Array(9).fill().map(() => ({}));
foo1(hits).then(() => {
console.log(hits);
});
There is also Promise.all
, which you could probably use (though not sure how wonderful that would be, I'm not a frequent Promise
user).
Update: Using Promise.all
function doAsyncStuff(item) {
return new Promise(resolve => {
const time = Math.ceil(Math.random() * 2000 + 1000);
window.setTimeout(() => {
item.someprop = time;
resolve();
}, time);
});
}
function foo1(arr) {
return Promise.all(
arr.map((item, index) => index % 2 === 0 && doAsyncStuff(item))
);
}
const hits = new Array(9).fill().map(() => ({}));
foo1(hits).then(() => {
console.log(hits);
});
I still haven't figured out the best way to format ES6, it always seems to end up with longish lines. (personal styling issue) :)
Upvotes: 0
Reputation: 3308
I would use Bluebird Promises and the reducer pattern.
var Promise = require('bluebird');
// iterates over the array 'arr' and calls fn
// Myfn repeatedly, optionally passing an initial.
// for the 1st iteration. For subsequent iterations,
// the value returned by prev invocation of Myfn is passed.
Promise.reduce(arr, Myfn, someInitialValue);
function Myfn(prev, item) {
//return a value or a promise.
}
see documentation of Reduce here: http://bluebirdjs.com/docs/api/promise.reduce.html
Upvotes: 0
Reputation: 3226
Looping and doing async stuff is a little tricky in JS. You could use one of the libraries that @smnbbrv mentioned in his comment. But you could also do it yourself, which can help you understand how some of these libraries work.
function foo1(arr) {
next(arr, 0)
}
function doAsyncStuff(item, cb) {
parser.parseURL(someurl, function(error, result) {
item.someprop = result.someprop;
cb(result);
})
}
function next(arr, i) {
// Stop when we reach the end of the array.
if (i >= arr.length) {
return;
}
if (i == 8) { // or any condition
// Move to the next item only when the async work is done.
doAsyncStuff(arr[i], function() {
next(arr, i + 1)
})
} else {
next(arr, i + 1)
}
}
Upvotes: 1