Jimmy D
Jimmy D

Reputation: 5376

Javascript async get request inside loop

I have an array of objects that looks like this:

[ { firstName: 'Mike', lastName: 'Jones' },
  { firstName: 'Joe', lastName: 'Smith' },
  { firstName: 'Bob', lastName: 'Johnson' } ]

I need to pass that array to a function that's going to add a "middleName" field to each object, and a value for middleName. The function gets the middle name by making an asynchronous http.get request in Node. And therein lies the problem. I can't make this work no matter how I try.

Previously someone suggested a loop like this:

array.forEach(function (obj) {
        GetMiddleName(obj, function (person) {
            obj.MiddleName = person;
        });
    });

But that doesn't work due to the async nature of the get being called in the GetMiddleName function. Can anyone show me a short, simple function that will do what I need?

Upvotes: 0

Views: 590

Answers (4)

feedy
feedy

Reputation: 1140

You need to create an array of promises and then resolve them. I think some of the answers here are correct but this is cleaner and easier to understand, especially if you are new to promises.

let promises = [];

array.forEach(function (item) {
  let promise = new Promise(function (resolve) {
    GetMiddleName(obj, function (person) {
        obj.MiddleName = person;
        resolve();
    });
  });

  promises.push(promise);
});

Promise.all(promises).then(function () {
  // Do something after all values/promises have been resolved
  // If not just leave it at Promise.all(promises)
});

Upvotes: 0

Maximilian Fixl
Maximilian Fixl

Reputation: 688

You could use the async package to handle asynchronous iterations by using the async framework.

Using async.eachOf without callback function (returns promise). Note: available from version 3.x.

Returns:
a promise, if a callback is omitted

Type: Promise

const async = require('async');

let items = [
    { firstName: 'Mike', lastName: 'Jones' },
    { firstName: 'Joe', lastName: 'Smith' },
    { firstName: 'Bob', lastName: 'Johnson' }
];

async.eachOf(items, (item, index, callback) => {
    GetMiddleName(item, function (person) {
        item.MiddleName = person;
    })
      .then(result => {

          console.log('this is result:', result);
          callback();
      });
})
.then(() => {
   console.log('All items updated');
});

Or you can handle it with callback function like this:

async.eachOf(items, (item, index, callback) => {
    GetMiddleName(item, function (person) {
        item.MiddleName = person;
    })
      .then(result => {

          console.log('this is result:', result);
          callback();
      });
},
  (err) => {
    if (err)
        throw new Error(err);
    else
        console.log('All items updated');
  });

Upvotes: 0

Confidence Yobo
Confidence Yobo

Reputation: 128

This should work

let arrData = [ { firstName: 'Mike', lastName: 'Jones' },
  { firstName: 'Joe', lastName: 'Smith' },
  { firstName: 'Bob', lastName: 'Johnson' } ];

  function getMiddleName(arr){
    arr.forEach(ar => {
        //this will be your async request that gets the usrename
        asynRequest.then(person => {
        arr.MiddleName = person;
      });
    });
  }

 getMiddleName(arrData);`

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 370639

Make an array of Promises, call Promise.all on that array, and then insert the middle name to each:

const getMiddleNameProm = obj => new Promise((resolve) => {
  GetMiddleName(obj, resolve);
});
Promise.all(arr.map(getMiddleNameProm))
  .then((middleNames) => {
    for (let i = 0; i < middleNames.length; i++) {
      arr[i].MiddleName = middleNames[i];
    }
    // do stuff with populated arr here
  });
});

Upvotes: 1

Related Questions