Reputation: 94
I'm trying to use the curseforge API in a project using fetch in nodejs18, this is the code I'm using:
ids = ["238222","60089","556448"]
const headers = {
'Accept':'application/json',
'x-api-key':'API KEY'
};
function getMods(id){
fetch("https://api.curseforge.com" + '/v1/mods/' + id,
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body.data.name);
});
}
ids.forEach(element => {
getMods(element)
});
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
console.log("download finished")
With that code what you want to be printed in the terminal is:
Alex's Delight
Mouse Tweaks
Just Enough Items (JEI)
download finished
but when running the program I get this in the terminal:
download finished
Alex's Delight
Mouse Tweaks
Just Enough Items (JEI)
This happens because the fetch function is asynchronous, I have tried all the methods to solve this problem but no solution is what I want.
What I want is for the program to wait for the foreach and fetch to finish to continue executing.
Upvotes: 0
Views: 1792
Reputation: 2665
Since you run nodejs 18 you can use top level await
const ids = ["238222", "60089", "556448"]
const headers = {
'Accept': 'application/json',
'x-api-key': 'API KEY'
};
async function getMods(id) {
await fetch("https://api.curseforge.com" + '/v1/mods/' + id, {
method: 'GET',
headers: headers
})
.then(res => res.json())
.then(body => {
console.log(body.data.name);
});
}
try {
await Promise.all(ids.map(id => getMods(id)))
console.log("download finished")
} catch {
// Handle error
console.error("download error")
}
Upvotes: 0
Reputation: 99533
Here's roughly how it's done:
const ids = ["238222","60089","556448"]
const headers = {
'Accept':'application/json',
'x-api-key':'API KEY'
};
async function getMods(id){
const res = await fetch("https://api.curseforge.com" + '/v1/mods/' + id, {
method: 'GET',
headers,
})
const body = await res.json();
console.log(body.data.name);
}
async function run() {
for(const element of ids) {
await getMods(element);
}
console.log("download finished")
}
run();
If you want to download the mods in parallel instead of one at a time, this is how the run()
function should look like instead:
async function run() {
await Promise.all(
ids.map(element => getMods(element))
);
console.log("download finished")
}
If you use ESM, you can avoid the 'run' function and just use await at the top-level. To easily take advantage of that with node, just save your file with the .mjs
extension.
Then the final code might look like this:
const ids = ["238222","60089","556448"]
const headers = {
'Accept':'application/json',
'x-api-key':'API KEY'
};
async function getMods(id){
const res = await fetch("https://api.curseforge.com" + '/v1/mods/' + id, {
method: 'GET',
headers,
})
const body = await res.json();
console.log(body.data.name);
}
await Promise.all(
ids.map(element => getMods(element))
);
console.log("download finished")
Upvotes: 1
Reputation: 1364
Something like this can work:
...
promisesArray = []
ids.forEach(element => {
promisesArray.push(getMods(element))
});
Promise.all(promisesArray).then(() => {
console.log("download finished");
});
Upvotes: 0