karthik110885
karthik110885

Reputation: 73

Waiting for a function to complete before executing the next step - Node.js

I am new to Node.js and currently learning about promises and await/async. I tried the below code but couldn't figure out how to make the code wait till the function hostping is finished. I have also tried promises but couldn't make it wait.

var ping = require('ping');
var hoststatus
var hosts = ['google.com'];

async function test()
{
  var connected = await hostping(hosts);
  console.log('connected--------------', connected)
  connected.then(function(hoststatus) {
    console.log('hoststatus--------------', hoststatus)
    if (hoststatus == 1) {
      console.log('faaaaaaaail-------------')
    } else {
      console.log('passssssssssssssssss-----------')
    }
  });
}

async function hostping(hosts) {
  console.log('hosts-----------', hosts)
  await hosts.forEach(async function(host) {
    await ping.sys.probe(host, async function(isAlive) {
      var msg = isAlive ? 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
      console.log(msg);
      if (isAlive == 'false') {
        hoststatus = 1
      }
    });
  });

  return hoststatus;
}

test()

Upvotes: 2

Views: 1365

Answers (3)

ksankar
ksankar

Reputation: 485

To do what you want, you should use the promise wrapper of ping and also for..of because forEach doesn't work with async.

  • The hostping function has to return a promise that test will wait for.
  • Use for of inside to loop over the hosts
  • use the promise wrapper of ping and wait for probe result
  • After all hosts are checked resolve the overall status

Below is modification of your code to get the flow working as you expected:

const ping = require('ping');
const hosts = ['google.com', 'yahoo.com'];

async function test()
{
  const status = await hostping(hosts);

    if (status) {
        console.log('All hosts are alive');
    } else {
        console.log('Some/all hosts are dead');
    }

}

function hostping(hosts) {
    let status = true;
    return new Promise(async function(resolve, reject) {
      for (const host of hosts) {
        const res = await ping.promise.probe(host);
        var msg = `host ${host} is ${res.alive ? 'alive' : 'dead'}`;
        console.log(msg);
        if (!res.alive) { status = false; }
      }
        console.log('all host checks are done, resolving status');  
        resolve(status);
    });
}

test()

If you're interested in understand more about async, these are good posts to read: https://www.coreycleary.me/why-does-async-await-in-a-foreach-not-actually-await/

https://itnext.io/javascript-promises-and-async-await-as-fast-as-possible-d7c8c8ff0abc

Upvotes: 1

Terry Lennox
Terry Lennox

Reputation: 30725

This should do what you wish, we use a for .. of loop to iterate the hosts in order.

The ping library also has a promise wrapper that allows you to skip using callbacks.

You could also use Promise.all to do all the pings and probes at once, but I don't believe this is what you wish to do.

I have included a hostpingVer2 that uses Promise.all if you want to do all pings at once.

const ping = require('ping');
const hosts = ['google.com', 'amazon.com', 'itdoesntexist'];

async function test() {
    console.log('hosts: ', hosts)
    const results = await hostping(hosts);
    console.log('ping results: ', results);
}

async function hostping(hosts) {
    const results = [];
    for(let host of hosts) {
        let probeResult = await ping.promise.probe(host);
        results.push( { host, hoststatus: probeResult.alive ? 0: 1, alive: probeResult.alive } );
    }
    return results;
}

async function hostpingVer2(hosts) {
    const probeResults = await Promise.all(hosts.map(host => ping.promise.probe(host)));
    return probeResults.map(probeResult => { 
        return { host: probeResult.host, hoststatus: probeResult.alive ? 0: 1, alive: probeResult.alive } 
    });
}

test();

Upvotes: 1

Ashish Modi
Ashish Modi

Reputation: 7770

You are using await inside forEach which is not supposed to work as forEach doens't support promises. Consider changing it to for..of or promise.all.

Also, your probe function is a callback style which doesn't return promise. You need to wrap it in a promise to await it.

function probe(host) {
  return new Promise((resolve, reject) => {
    ping.sys.probe(host, function (isAlive) {
      const msg = isAlive ? `host ${host} is alive` : `host ${host} is dead`;
      console.log(msg);
      resolve(isAlive);
    });
  });
}

async function hostping(hosts) {
  console.log("hosts-----------", hosts);
  for(const host of hosts) {
    // eslint-disable-next-line no-loop-func
    // eslint-disable-next-line no-await-in-loop
    const isAlive = await probe(host);
    if (isAlive === "false") {
      hoststatus = 1;
    }
  }
  return hoststatus;
}

Upvotes: 0

Related Questions