0

I have the following code that is used to get JSON data from an Amazon Web Server API.

var json1 = new Promise((resolve, reject) => {
     fetch(url[0])
     .then(r => {
         resolve(r.json())
     })
     .catch(err => {
         reject(err)
     })
})

I have this repeating 14 times using different urls and json vars and have it return the promises at the end using.

return Promise.all([json1,json2,json3,json4,json5,json6,json7,json8,json9,json10,json11,json12,json13,json14]).then(function(values) {
    return values;
});

This works, but it takes up 150+ lines. I want to make a for loop that runs through the same code using a for loop. I created this...

for(var jsonCount = 0;jsonCount<url.length-1;jsonCount++){
    jsonArr[jsonCount] = new Promise((resolve, reject) => {
        fetch(url[jsonCount])
        .then(r => {
            resolve(r.json())
        })
        .catch(err => {
            reject(err)
        })
    })
}

This doesn't work because the promise functions come back as undefined even though it is called by an await function.

const data = await fetchURL(urlToQuery())

Does anyone have suggestions to make this work? There is JSON being returned.

Thanks for your help.

Edit: Here is a larger chunk of the code.

function fetchURL(urls) {
    let fetchJson = url => fetch(url).then(response => response.json());
    Promise.all(urls.map(fetchJson)).then(arr => {
        return arr;
    });
(async function() {
    const data = await fetchURL(urlToQuery())
    console.log(data);
        for(var r=0;r<numStations;r++){
            if (data[r] == ""){
                onlineArr[r] = false;
                wdDataArr[r].push(cardinalToDeg(stationHistAvgArr[r]));
                wsDataArr[r].push(0);
BMW
  • 35
  • 7

4 Answers4

1

You can use .map for the loop. But don't use new Promise. You don't need a new promise when fetch already provides you with one. Also, call your array urls instead of url. A plural will be a good indication for the reader of your code that indeed it is a collection of URLs.

Here is how it could look:

let fetchJson = url => fetch(url).then(response => response.json());

Promise.all(urls.map(fetchJson)).then(arr => {
    // process your data
    for (let obj of arr) {
        console.log(obj);
    }
});
trincot
  • 317,000
  • 35
  • 244
  • 286
  • I got the data when I used `console.log(arr)` but when I `return arr;` to the async function, I dont get any data. any advice? – BMW Jun 10 '20 at 18:45
  • I added a larger chunk of code above. Thanks for your help. – BMW Jun 10 '20 at 18:50
  • That's because your function `fetchURL` does not return anything. You should `return` the promise that `Promise.all()` returns. – trincot Jun 10 '20 at 18:55
  • How do you do that? Sorry, I'm really unfamiliar with Promises. – BMW Jun 10 '20 at 19:04
  • There is nothing special about it. Just put the `return` keyword before `Promise.all`. The `all` method returns a promise (its just an object), and you need to return it. Otherwise your function returns nothing at all (`undefined`). – trincot Jun 10 '20 at 19:18
0

I think this example can helps you:

// Mock async function
const getDataAsync = callback => {
    setTimeout(
        () => callback(Math.ceil(Math.random() * 100)),
        Math.random() * 1000 + 2000
    )
}

// Create the promise
const getDataWithPromise = () => {
    return new Promise((resolve, reject) => {
        try {
            getDataAsync(resolve);
        } catch(e) {
            reject(e);
        }
    });
}

// Using the promise one time
getDataWithPromise()
    .then(data => console.log("Simple promise:",data))
    .catch(error => console.error(`Error catched ${error}`));

// Promises compound: Promise.all
const promise1 = getDataWithPromise();
promise1.then(data => console.log("promise1 ends:",data));
const promise2 = getDataWithPromise();
promise2.then(data => console.log("promise2 ends:",data));
const promise3 = getDataWithPromise();
promise3.then(data => console.log("promise3 ends:",data));
const promise4 = getDataWithPromise();
promise4.then(data => console.log("promise4 ends:",data));
const promise5 = getDataWithPromise();
promise5.then(data => console.log("promise5 ends:",data));

Promise.all([promise1,promise2,promise3,promise4,promise5])
    .then(data => console.log("Promise all ends !!",data));

Hope this helps

0

you will have issues with closure and var variable capture.

You may want to change var to let to capture the right value in the closure so that url[jsonCount] is actually what you want.

also I think it would be much easier to do something like that in one line :)

let results = [];
for(let i = 0; i < urls.length; ++i) results.push(await (await fetch[urls[i]]).json());
fred_
  • 1,486
  • 1
  • 19
  • 31
  • I get an error of ```Uncaught SyntaxError: missing ) after argument list``` on the second line. I tried to make changes, but I always got this error. Any advice? – BMW Jun 08 '20 at 18:15
  • can you post the modified code? the number of ) looks ok – fred_ Jun 08 '20 at 18:53
  • I copy and pasted the code from your answer. This is what I have. ```let results = []; for(let i = 0; i < urls.length; ++i) results.push(await (await fetch[urls[i]]).json()); return results;``` – BMW Jun 08 '20 at 19:17
  • ```for(let i = 0; i < url.length; i++) results.push(await (await fetch(url[i])).json());``` still hits the same error. url is a parameter that is in the function being called. – BMW Jun 08 '20 at 19:31
0

This is a good use for map, mapping urls to promises...

function fetchUrls(urls) {
  let promises = urls.map(url => fetch(url))
  return Promise.all(promises).then(results => {
    return results.map(result => result.json())
  })
}}

// url is your array of urls (which would be better named as a plural)
fetchUrls(url).then(results => {
  // results will be the fetched json
})

Using the async/await syntax (equivalent meaning)

// this can be called with await from within another async function
async function fetchUrls(urls) {
  let promises = urls.map(url => fetch(url))
  let results = await Promise.all(promises)
  return results.map(result => result.json())
}
danh
  • 62,181
  • 10
  • 95
  • 136