18

i have this problem: i want to make multiple fetch calls within a for-loop. The number of calls depend on the user input (in my example i have three). How can i make it loop through all the fetch requests and then console.log the number off calls?

function getPosts(){

  let url = ["https://www.freecodecamp.org", "https://www.test.de/, http://www.test2.com"];
  let array = new Array;

  for (let i = 0; i < url.length; i++) {
    console.log(url[i]);
    fetch(url[i])
    .then(res => {return res.text(); })
    .then(res => {
            let reg = /\<meta name="description" content\=\"(.+?)\"/;
            res = res.match(reg);
            array.push(res);
            console.log(res);
          }
    )
    .catch(status, err => {return console.log(status, err);})
  }
  console.log (array.length);
  }

It console.logs 0 instead of 3, cause it doesn't wait for all the promises to be resolved. How can i make it to console.log 3? If you know a solution, please help me out.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
Timo Hoehn
  • 181
  • 1
  • 1
  • 3

5 Answers5

15

You can't call console.log(array.length) until after the promises are all done. So why not something like this?

let url = ["https://www.freecodecamp.org", "https://www.test.de/, http://www.test2.com"];
  let array = new Array;
  var fetches = [];
  for (let i = 0; i < url.length; i++) {
    console.log(url[i]);
    fetches.push(
      fetch(url[i])
      .then(res => {return res.text(); })
      .then(res => {
            let reg = /\<meta name="description" content\=\"(.+?)\"/;
            res = res.match(reg);
            array.push(res);
            console.log(res);
          }
      )
      .catch(status, err => {return console.log(status, err);})
    );
  }
  Promise.all(fetches).then(function() {
    console.log (array.length);
  });
  }

Promise.all waits for all the fetches to finish, THEN it'll print the #.

Josh
  • 2,958
  • 3
  • 16
  • 27
  • 2
    thanks for the idea. it does work, but only if all the fetch requests are succesfully resolved...do you know how i can have the console.log, if one of the fetch requests fail? – Timo Hoehn Jun 24 '18 at 19:56
  • Promise.all(fetches).then(function() { console.log (array.length); }).catch(function(e){ todo: log error e}) ? – st35ly Sep 15 '21 at 03:12
6

You can use async/await with try/catch:

async function getPosts(){
  let array = [];
  let url = ["https://www.freecodecamp.org", "https://www.test.de/", "http://www.test2.com"];
  let reg = /\<meta name="description" content\=\"(.+?)\"/;
  for (let i = 0; i < url.length; i++)   {
    console.log('fetching',url[i]);
    try {
      let p1 = await fetch(url[i]);
      let p2 = await p1.text();
      let res = p2.match(reg);
      array.push(res);
      console.log('adding',res);
    }
    catch (e) {
      console.error(e.message);
    }
  };
  console.log ('length',array.length);
};

getPosts().then(()=>{console.log('done')});
amaksr
  • 7,555
  • 2
  • 16
  • 17
0

You can try chaining your promises, Try the following:

function getPosts(){

  let url = ["https://www.freecodecamp.org", "https://www.test.de/, http://www.test2.com"];
  let array = new Array;
  var promise = Promise.resolve();
  for (let i = 0; i < url.length; i++) {
    console.log(url[i]);
    promise = promise.then(fetch(url[i]))
    .then(res => {return res.text(); })
    .then(res => {
            let reg = /\<meta name="description" content\=\"(.+?)\"/;
            res = res.match(reg);
            array.push(res);
            console.log(res);
          }
    )
    .catch(status, err => {return console.log(status, err);})
  }
  promise.then(function(response){
    console.log (array.length);
  });
}
amrender singh
  • 7,949
  • 3
  • 22
  • 28
0

You should use promise, A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.

const fetch = require('node-fetch')
let url = ["https://www.freecodecamp.org", "https://www.test.de/, http://www.test2.com"];
let array = new Array;
function get(url) {
  return new Promise((resolve, reject) => {
    fetch(url)
      .then(res => { return res.text(); })
      .then(res => {
        let reg = /\<meta name="description" content\=\"(.+?)\"/;
        res = res.match(reg);
        resolve(res)
        //console.log(res);
      }
      )
      .catch(err => { reject(err) })
  });
}
async function result() {
  for (let i = 0; i < url.length; i++) {
    const value = await get(url[i]);
    array.push(value)

  }
  console.log(array.length)
}

result()

==> array.length = 2,

Selmi Karim
  • 2,135
  • 14
  • 23
0

You can use async await ( async: function, await: operator ). Await operator simply wait for the promise to be resolved. First promise will be resolved then it will move to another one. Also, if it finds error in any fetch, it will catch the error right away.