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
CodePudding user response:
getLink
is never called in your code.- Even, if it is called, when
Promise.all(promises)
runs, thepromises
array is still be empt because it is populated in thethen
callback which runs later - You are pushing the
url
from the response to the array instead of pushing the actual promises returned by axios
const 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)
CodePudding user response:
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)
}
CodePudding user response:
//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
})