1

First of all I did read through similar questions, and still cannot see where I'm making my mistake.

Here's my code:

async function validateWebsites(website) {
    var result = url.parse(`http://${website}`);
    console.log(result.hostname);
    return await fetch(`http://www.${result.hostname}`)
        .then(() => console.log(true))
        .catch(() => console.log(false));
}
var wrongWebsites = [];

    var wrongWebsites = [];

var i = 0;
websites.forEach(website => {
    i++;
    if (validateWebsites(website) === false
    ) {
        wrongWebsites.push(i);
    }
});

console.log(wrongWebsites);

How it works:

The user passes an array of websites, and I want to validate if they're valid websites, not to waste resources and block other errors. Now to the console:

digitlead.com
google.com
georgiancollege.ca
youtube.com
    []
true
true
true
true

So as you see, it prints out first the websites array, and then the response. So it's still async. How do I make it wait? I changed the loop from a for to forEach as suggested by many posts, I used the await and I am returning a promise. So what else do I have to do?

Edit:

I tried to do this:

async function validateWebsites(website) {
    var result = url.parse(`http://${website}`); // TODO figure out if filtering all the subpages is a good idea.
    console.log(result.hostname);
    return await fetch(`http://www.${result.hostname}`)
        .then(()=>console.log(true))
        .catch(()=>console.log(false));
}

But it doesn't change anything

I found a function called readFileSync. That's more or less what I'm looking for, but with the ability to call a different website.

Alex Ironside
  • 4,658
  • 11
  • 59
  • 119
  • Async functions are still .... asynchronous. The syntax is just for show, to make it so you can write the code in a sync way. If you want them to be done 1 at a time you will have to chain the promises returned from the async function. – Patrick Evans Apr 24 '18 at 17:41
  • `async` function returns a promise - you have to `await` inside the loop itself. – pishpish Apr 24 '18 at 17:42
  • Ok now I'm really confused. Can you post an example? I'll edit my code to show what I tried now. – Alex Ironside Apr 24 '18 at 17:52
  • note that `validateWebsites` will always resolve to `undefined` because of `console.log` – Maciej Kozieja Apr 24 '18 at 18:18

2 Answers2

0

Here is how you can get all valid websites.
Problem with your validateWebsites function is that it returns promise wchih is resolving to undefined thanks to promise chaining and your loging

Also using forEach to filter array is unnesesery.
But if you wanted you could do something like this

websites.forEach(async website => {
    i++;
    if (await validateWebsites(website) === false) { // now value is Boolean instead of Promise
        wrongWebsites.push(i);
    }
});

Also note that if you use global i with asyncronous functions to keep track of index this can lead to many errors.

However I think this soultion should satisfy you

async function validateWebsites(website) {
  var result = url.parse(`http://${website}`)
  return fetch(`http://www.${result.hostname}`)
    .then(() => true) // async function returns promise
    .catch(() => false)
}

const websites = ['digitlead.com',
  'google.com',
  'georgiancollege.ca',
  'youtube.com',
  '111.1',
  'foobarbaz']

async function filter(array, func) {
  const tmp = await Promise.all( // waits for all promises to resolve
    array.map(func) // evecutes async function and stores it result in new array then returns array of promises
  ) 
  return array.filter((_, i) => tmp[i]) // removes invalid websites
}

const validWebsites = filter(websites, validateWebsites)

validWebsites.then(console.log) 

Get the indexes of the non-valid sites

async function filter(array, func) {
  const tmp = await Promise.all(array.map(func))
  return tmp
         .map((x, i) => !x && i) // flip true to false and asign index when x is false
         .filter(x => x !== false) // return indexes
}
Maciej Kozieja
  • 1,812
  • 1
  • 13
  • 32
-1

destoryeris saying you should do something like this:

websites.forEach(async website => {
    i++;
    if (await validateWebsites(website) === false
    ) {
        wrongWebsites.push(i);
    }
});

But that alone is problematic because you have wrap your async functions in a try/catch to handle their errors. So something more like this:

websites.forEach(async website => {
    i++;

    try {
      const validSites = await validateWebsites(website); 
      if (validSites === false) {
        wrongWebsites.push(i);
      }
    } catch(e) {
        // handle e
    }
})
Max Baldwin
  • 3,404
  • 3
  • 26
  • 40
  • Actually he handles errors by using `.catch` in `validateWebsites` thanks to this `await validateWebsites(website)` will never throw – Maciej Kozieja Apr 24 '18 at 18:24
  • @MaciejKozieja the console will throw a warning if you don't use `try/catch` to handle `async/await` errors. Yes, he is handling them in his promise chain, but the `then/catch` only tell the async function how to handle the results. You have to use `try/catch` to tell the async function where to put the error or the error will get swallowed. – Max Baldwin Apr 24 '18 at 19:12
  • In this case I would agre only if we care about connection errors otherwhise returning bool and swallowing error for me is fine – Maciej Kozieja Apr 24 '18 at 19:19
  • `returning bool and swallowing error for me is fine` <-- Lol! What if the service he is fetching is returning 500 errors? @MaciejKozieja – Max Baldwin Apr 24 '18 at 19:24
  • Then its simple 'nobody cares', goal of `validateWebsites` function is to check if url is valid that means it can be fetched. Since code will run on server side probably (because of `cross-domain-request` in browser won't alow it any way) I supose internet will be provided all the time so evry other error means that it is just not avaliable – Maciej Kozieja Apr 24 '18 at 19:31