Reputation: 49
I have this array of objects
const items = [
{
quantity: '2',
name: 'john',
type: 'https://api/event/1',
},
{
quantity: '3',
name: 'jane',
type: 'https://api/event/2',
}
]
for each object in the array, I need to call the API n
number of times depending on the object quantity
value. Calling the API will basically generate a unique link. I know this is not the best for performance but this is a small app and we'd be making between 3-5 api calls in the worst case scenario, usually 1 tbh. In this case, I have 2 objects in the array, the first has 2 API calls and the second has 3 API calls. Every time I call the API I want to save the result (unique link) in an array so that I can email them to the customer who bought them.
This is what I have tried so far but it hasn't worked:
const promises = []
const getLinks = async (arr) => {
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].quantity; j++) {
const getLink = (owner) => {
axios.request({
method: 'POST',
url: 'https://api.call'
})
.then(function (response) {
const promise = response.data.url
promises.push(promise)
})
.catch(error => console.log(error))
}
}
}
const links = await Promise.all(promises)
console.log('links:', links) // === [] this is always empty ===
}
getLinks(items)
One thing I learned is that await cannot be and will slow down the code drastically inside loops
I can't seem to get it to work
Upvotes: 2
Views: 619
Reputation: 1259
// Update your code like the following, I tested on my side and its working and easy
const axios = require("axios");
const items = [
{
quantity: "2",
name: "users",
type: "https://jsonplaceholder.typicode.com/users/1",
},
{
quantity: "3",
name: "posts",
type: "https://jsonplaceholder.typicode.com/posts/1",
},
];
const allPromises = items
.map((eachObject) => {
const { type: url, quantity } = eachObject;
const promiseArray = new Array(Number(quantity)).fill(axios.get(url));
return promiseArray;
})
.reduce((prev, current) => {
return [...prev, ...current];
}, []);
Promise.all(allPromises)
.then((res) => {
if (res instanceof Array) {
const result = res.map((each) => each.data);
console.log("result is", result);
} else {
console.log("not an array");
}
})
.catch((err) => console.error(err))
.finally(() => console.log("done!"));
Upvotes: 0
Reputation: 9
//Map methods return an array
const apiResponse = items.map(async(apiCall) => {
// call an api here and store its result in a veriable
let returnedResult
await axios.get(apiCall.type)
.then(response => {
//refactor the reponse to how you want to store it in the array
returnedResult = response
})
return returnedResult
})
Promise.all(apiResponse)
.then(response => {
console.log(response)
// sent an email here based on the response you get
})
Upvotes: 0
Reputation: 113906
You are a bit confused about how Promises work.
/* THIS THING IS A PROMISE -> */ axios.request({
method: 'POST',
url: 'https://api.call'
})
.then(function (response) {
const promise = response.data.url // <-THIS THING IS NOT A PROMISE
})
The Promise
is the value of axios.request()
. Therefore if you want the promise you should do this:
const promise = axios.request();
The value inside the .then()
is NOT a Promise
!! It is the value returned by the promise:
const promoise = axios.request({
method: 'POST',
url: 'https://api.call'
})
.then(function (response) {
const result = response.data.url;
return result;
})
Therefore you have been pushing the completely wrong thing to your promises
array! You have been pushing the URL string returned by your api call instead of the promises.
To get your code working correctly is extremely simple:
const getLinks = async (arr) => {
let promises = []
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].quantity; j++) {
const getLink = (owner) => {
const promise = axios.request({
method: 'POST',
url: 'https://api.call'
})
.then(function (response) {
return response.data.url
})
.catch(error => console.log(error))
promises.push(promise)
}
}
}
const links = await Promise.all(promises)
console.log('links:', links)
}
Upvotes: 0
Reputation: 35222
getLink
is never called in your code.Promise.all(promises)
runs, the promises
array is still be empt because it is populated in the then
callback which runs laterurl
from the response to the array instead of pushing the actual promises returned by axiosconst promises = []
for (const o of items) {
for (let i = 0; i < o.quantity; i++) {
const promise = axios.request({ method: post, url: o.type })
promises.push(promise)
}
}
const responses = await Promise.all(promises)
const urls = responses.map(r => r.data.url)
Or,
you could use flatMap
get an array of all the promises returned by axios and use Promise.all
on the resulting array
const promises = items.flatMap(o =>
Array.from({ length: o.quantity }, _ => axios.request({ method: post, url: o.type })
)
const responses = await Promise.all(promises)
Upvotes: 1