0

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!

3
  • Read about async library.... Commented Sep 11, 2016 at 7:29
  • callback, promise, rxjs, async / await. Any of them will help you in this case. But only the last one will allow you to really make a for loop Commented Sep 11, 2016 at 7:32
  • Not very related, but you have a typo: fucntion Commented Sep 11, 2016 at 8:07

3 Answers 3

1

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)
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

0

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) :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.