Stian Instebo
Stian Instebo

Reputation: 652

Promise never settles - NodeJS

I've made the following loop, where I loop an Array; and then doing a quick GET request for each of them.

I made the loop work and the data is logged correctly. However the "loop" never finishes, and therefore not reaching ().then => {}

Promise.all(
    arr.map((key,item) => {
    return new Promise((resolve,reject) => {
        var costmicro = 0;
        request.post({
            url: 'https://googleads.googleapis.com/v8/customers/'+arr[item]+'/googleAds:searchStream',
            headers: {
                'Content-Type': 'application/json',
            },
            json: {
                "query": "SELECT metrics.cost_micros FROM campaign WHERE segments.date DURING LAST_30_DAYS",
            }
            }, function (errAdsCampaign, httpResponseAdsCampaign, bodyAdsCampaign) {
                if (!errAdsCampaign) {
                for (ii in bodyAdsCampaign[0].results) {
                    costmicro = costmicro+parseInt(bodyAdsCampaign[0].results[ii].metrics['costMicros']);
                    var arrlength = bodyAdsCampaign[0].results.length-1;
                        if (ii == arrlength) {
                            objectArray.push({name: arr[item], cost: costmicro / 1000000});
                            resolve(objectArray);
                        }
                }
            } else {
                reject();
            }
        });
    });
    })
).then(()=>{
    console.log('done');
    console.log(objectArray)
}).catch(() => {
    console.error;
});

UPDATE Replaced the catch() function. Like so; sadly it never returns an error, and never finished

}).catch((e) => {
    console.error(e);
});

Any help is much appreciated!

Upvotes: 0

Views: 87

Answers (3)

ikhvjs
ikhvjs

Reputation: 5977

The library request has been deprecated. Ref. https://www.npmjs.com/package/request

Instead, I would suggest using axios.

(async function run() {
  try {
    const objectArray = await Promise.all(
      arr.map(async (key, item) => {
        const res = await axios.post(
          "https://googleads.googleapis.com/v8/customers/" +
            arr[item] +
            "/googleAds:searchStream",
          {
            json: {
              query:
                "SELECT metrics.cost_micros FROM campaign WHERE segments.date DURING LAST_30_DAYS",
            },
          },
          {
            headers: {
              'Content-Type': 'application/json',,
            },
          }
        );

        const costmicro = res.data.bodyAdsCampaign.results.reduce((acc, cur) => {
          acc += cur.metrics["costMicros"];
          return acc;
        }, 0);

        return { name: arr[item], cost: costmicro / 1000000 };
      })
    );

    console.log(objectArray);
  } catch (err) {
    console.log(err);
  }
})();

Upvotes: 0

mpu
mpu

Reputation: 400

Inside your function inside the loop, you need to account for all possible exit paths and call either resolve() or reject(). One such exit path that is not handled is if bodyAdsCampaign[0].results is an empty array or undefined. In this case, the function will finish running without calling resolve() or reject().

You can also add a call to reject() at the end of your function (errAdsCampaign, httpResponseAdsCampaign, bodyAdsCampaign) callback function to catch all scenarios which aren't handled within the function.

Upvotes: 3

mpu
mpu

Reputation: 400

Your code inside the loop likely threw an error and it skipped the .then() clause and went to the .catch() clause. You can replace the .catch() clause with the code below to see what error was encountered.

}).catch((e) => {
    console.error(e);
});

Upvotes: 0

Related Questions