0

Basically I have a function which loops through all the elements from an api and pushes it to a array and then I return the array, but I am getting random of amount of elements everytime I run this function.

function getElements() {
    const url = "https://neelpatel05.pythonanywhere.com/element/atomicnumber?atomicnumber=";
    var elements = [];
    for(var i=1;i<=118;i++){
        newurl = url+i.toString();
        fetch(newurl)
        .then(response => response.json())
        .then(data => elements.push(data.symbol))
    }
    return elements;
}
console.log(getElements());

thanks in advance

11
  • how to use async/await you are asking the right question, you are on the right track. Have you tried it? Commented Jun 4, 2021 at 8:12
  • well i did learn about it but i dont how to implement them in the loop Commented Jun 4, 2021 at 8:14
  • 1
    BTW it's weird that you get a "random of amount of elements" in your array. According to this code, you should get exactly 0 element, because you return the array immediately, before it is filled by your... 118 concurrent asynchronous calls Commented Jun 4, 2021 at 8:14
  • i have no idea also i am javascript beginner so i dont know much about async and await Commented Jun 4, 2021 at 8:15
  • You did learn about it, so give it a try :) If you did learn about it, surely you can try and start to write something? I don't want to simply give you the solution on a plate, because I believe you are nearly there and you can do it with what you already know. Commented Jun 4, 2021 at 8:16

6 Answers 6

1

All the promises stored in elements will resolve together using Promise.all() method.

function getElements() {
    const url = "https://neelpatel05.pythonanywhere.com/element/atomicnumber?atomicnumber=";
    var elements = [];
    for(var i=1;i<=118;i++){
        newurl = url+i.toString();
        const res = fetch(newurl)
        .then(response => response.json());
        elements.push(res);
    }
    return Promise.all(elements);
}
Sign up to request clarification or add additional context in comments.

Comments

1

Do not send so many request at a same time, send request in batches... Wait for 10 promise to finish, then next 10, then next 10, so on...

async function getElements() {
    const url = "https://neelpatel05.pythonanywhere.com/element/atomicnumber?atomicnumber=";
    let elements = [], pending = [];
    for(let i=1; i <= 118; i++){
        let p = fetch(url + i)
           .then(response => response.json())
           .then(data => elements.push(data.symbol))
           .catch(console.log);
         
        if (pending.push(p) > 10) {
            await Promise.all(pending);
            pending = [];
        }
    }
    return Promise.all(pending).then(() => elements);
}

// you cannot use async await in global scope, so I used 'then' here instead
getElements().then(elements => console.log(elements.length))

Comments

1

You need to push entire promise to array and wait for them all to be resolved, so they will be resolved in parallel.

function getElements() {
    const url = "https://neelpatel05.pythonanywhere.com/element/atomicnumber?atomicnumber="
    const elements = []
    for(let i=1;i <= 118; i++){
        newurl = url + i // no need to 'i.toString()'
        elements.push( // push entire promise, not just "unpacked" response
          fetch(newurl)
            .then(response => response.json())
            .then(data => data.symbol)
        )
    }
    return Promise.all(elements)
}

getElements().then(elements => {
  console.log(elements.length)
  console.log(elements)
})
.as-console-wrapper { max-height: 100% !important; top: 0; }

9 Comments

yesh i tried this and got this working but it take a hell lot of time to complete is there a way i can make it take less time ?
Yurgh no, this is ugly. You are mixing the async/await and the .then() syntaxes. It eventually works, so I won't downvote, but man is this inelegant
Yes, do not send 118 requests in a loop.
Or don't await each request and send them parallel?
it take a hell lot of time to complete is there a way i can make it take less time ? first, don't make 118 concurrent calls, give the server some time to breathe. Then, the results will always be the same (you are querying a periodic table) so do this once, store the results in a variable and reuse them.
|
0

Ok, here you go then (I have limited the number of calls to 3, to not hammer this poor server too much)

const url = "https://neelpatel05.pythonanywhere.com/element/atomicnumber?atomicnumber=";

const getElements = async () => {
    let elements = [];

    for(var i=1;i<=3;i++){
        newurl = url+i.toString();

        const response = await fetch(newurl);
        const data = await response.json()
        
        elements.push(data.symbol)
    }
    return elements; // This is a Promise of array, not an array, because an async function always returns a Promise of something. So this can be awaited.
};

(async () => {
    console.log(await getElements());
})();

Comments

0

You can send all requests at once and store the promises in an array. Then you can wait for all promises to resolve:

async function getElements() {
    const url = "https://neelpatel05.pythonanywhere.com/element/atomicnumber?atomicnumber=";
    const promises = [];
    for(var i=1;i<=118;i++){
        newurl = url+i.toString();
        promises.push(fetch(newurl));
    }
    return Promise.all(promises);
}
(async () => {
    const responses = await getElements();
    responses.forEach(async response => console.log(await response.json()));
})();

A server should be able to handle 118 requests at once but you shouldn't send too many requests.

Be aware that in this minimal example the order of the console.log usually is not the order you sent the requests. forEach doesn't consider awaits.

6 Comments

await doesn't work inside array methods like .forEach or .map.
@JeremyThille Of course, it works. Press "Run code snippet" and see how it awaits response.json().
@JeremyThille When I press "Run code snippet" I get 118 objects. It may not work on your platform for some reasons but usually it works. jsfiddle supports it: see jsfiddle.net/nzh4d1e3 and wait about 5 seconds
It works but doesn't do what you think it does. stackoverflow.com/questions/37576685/…
|
0

The minimal rule of using async and await is that await can be used in an async function. So if you don't care about parallelism, you can just wrap your entire test into a bigger async function, add the keywords here and there, and that's it:

async function main() {                  // <-- wrapper
    async function getElements() {       // <-- became async, so can use await
        const url = "https://neelpatel05.pythonanywhere.com/element/atomicnumber?atomicnumber=";
        var elements = [];
        for(var i=1;i<=118;i++){
            newurl = url+i.toString();
            await fetch(newurl)          // <-- await request right in the loop
            .then(response => response.json())
            .then(data => elements.push(data.symbol))
        }
        return elements;
    }
    console.log(await getElements());    // <-- await the async function
}
main();                                  // <-- call wrapper
console.log("! results will come after this line !"); // memo about the test still being async

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.