Reputation: 73
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
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.
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
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
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