Home > Enterprise >  How to return a array with objects from a nested async callback function inside a for of loop?
How to return a array with objects from a nested async callback function inside a for of loop?

Time:09-06

I'm trying to write a small program that will ping internal addresses to check if a server is down. The problem is that I cant get the timing right. If I put a console.log() inside the for of loop it returns the objects I want but several times of cource. If I write a console.log after the for of loop, I only get an empty array, probably because the loop is not finished yet.I have tried to fix this in various ways but keep running into problems. I use node-cmd to send an http ping as normal pings only work against domains.

You can ignore my nightmare regex :) It should just split the response into an array which is then pushed to object

var cmd = require('node-cmd');

const hosts = [
  'https://adressone.com',
  'https://adresstwo.com',
  'https://adressthree.com',
  'https://adressfour.com'
];
let results = [];
for (let host of hosts) {
  cmd.run(`http-ping.exe ${host}`,
    async function(err, data, stderr) {
      const result = await data.split('>');
      const resultDig = result[1].replace(/[^0-9\.] /g, " ").replace(/2$/g, "").trim().split(' ')

      results.push({
        host: host,
        status: resultDig[0],
        bytes: resultDig[1],
        time: resultDig[2],
      });

    }
  );
}
console.log(results);

The result I would like in console.log(results):

[{
    host: 'https://adressone.com',
    status: '200',
    bytes: '703',
    time: '640'
  },
  {
    host: 'https://adresstwo.com',
    status: '200',
    bytes: '703',
    time: '640'
  },
  {
    host: 'https://adressthree.com',
    status: '200',
    bytes: '703',
    time: '640'
  },
  {
    host: 'https://adressfour.com',
    status: '200',
    bytes: '703',
    time: '640'
  }
]

CodePudding user response:

The best approach for this question will be by using Promises in JavaScript.

An example for this implementation.

async function parseResult() {
  const hosts = [
    "https://adressone.com",
    "https://adresstwo.com",
    "https://adressthree.com",
    "https://adressfour.com",
  ];
  const promises = [];
  for (let host of hosts) {
    const response = new Promise(function (resolve, reject) {
      setInterval(async () => {
        resolve({
          status: "Success",
        });
      }, 1000);
    });
    promises.push(response);
  }
  const finalResult = await Promise.all(promises);
  return finalResult;
}
parseResult().then((res) => console.log(res));

OR

async function parseResult() {
  const hosts = [
    "https://adressone.com",
    "https://adresstwo.com",
    "https://adressthree.com",
    "https://adressfour.com",
  ];
  const promises = hosts.map(
    (host) =>
      new Promise(function (resolve, reject) {
        setInterval(async () => {
          resolve({
            status: "Success",
          });
        }, 1000);
      })
  );
  const finalResult = await Promise.all(promises);
  return finalResult;
}
parseResult().then((res) => console.log(res));

A Pseudo code for your question will be like below

var cmd = require("node-cmd");
async function parseResult() {
  const hosts = [
    "https://adressone.com",
    "https://adresstwo.com",
    "https://adressthree.com",
    "https://adressfour.com",
  ];
  let promises = [];
  for (let host of hosts) {
    const response = cmd.run(
      `http-ping.exe ${host}`,
      async function (err, data, stderr) {
        const result = await data.split(">");
        const resultDig = result[1]
          .replace(/[^0-9\.] /g, " ")
          .replace(/2$/g, "")
          .trim()
          .split(" ");

          // Returning a promise here
        return new Promise(function (resolve, reject) {
          resolve({
            host: host,
            status: resultDig[0],
            bytes: resultDig[1],
            time: resultDig[2],
          });
        });
      }
    );
    promises.push(response);
  }
  // promises array will hold a list of promises now
  // Await till all the promises are resolved and that will be your final result
  const finalResult = await Promise.all(promises);
  return finalResult;
}
parseResult().then((res) => console.log(res));

Explanation: Here the parseResult function loops through an array hosts and will run an async operation against each nodes in hosts array. The result of this operation is a Promise, so your final promises array will be holding a list of promises. Once all this promises are resolved, you will get your final result. You can detect when all your promises are resolved by using await Promise.all(promises)

CodePudding user response:

I'd suggest to use node-cmd-promise. I removed the splitting:

const cmd = require('node-cmd-promise')

const hosts = [
  'https://adressone.com',
  'https://adresstwo.com',
  'https://adressthree.com',
  'https://adressfour.com',
]

async function main() {
  const results = []
  for (const host of hosts) {
    const result = await cmd(`echo ${host}`)

    // Insert logic here
    const resultDig = [result.stdout, 'foo', 'bar']

    results.push({
      host,
      status: resultDig[0],
      bytes: resultDig[1],
      time: resultDig[2],
    })
  }
  console.log(results)
}

main()
  • Related