我有一个对象数组
const items = [
{
quantity: '2',
name: 'john',
type: 'https://api/event/1',
},
{
quantity: '3',
name: 'jane',
type: 'https://api/event/2',
}
]
对于数组中的每个对象,我需要根据对象的quantity
值调用APIn
次数。调用API基本上会生成一个唯一的链接。我知道这对性能来说不是最好的,但这是一个小应用程序,在最坏的情况下,我们会调用3-5个api,通常是1个。在这种情况下,我在数组中有2个对象,第一个有2个API调用,第二个有3个API调用。每次我调用API时,我都想将结果(唯一链接)保存在一个数组中,以便我可以将它们通过电子邮件发送给购买它们的客户。
这是我到目前为止尝试过的,但它没有工作:
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)
我学到的一件事是await不能并且会在循环中大幅降低代码速度
我似乎不能使它工作
getLink
在你的代码中从来没有被调用过。- 即使它被调用,当
Promise.all(promises)
运行时,promises
数组仍然是空的,因为它在then
回调中填充,稍后运行 - 您正在将
url
从响应推送到数组,而不是推送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)
,或者您可以使用flatMap
获取axios返回的所有承诺的数组,并在结果数组
Promise.all
。const promises = items.flatMap(o =>
Array.from({ length: o.quantity }, _ => axios.request({ method: post, url: o.type })
)
const responses = await Promise.all(promises)
你对承诺的工作方式有点困惑。
/* 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
})
Promise
为axios.request()
的值。因此,如果你想要这个承诺,你应该这样做:
const promise = axios.request();
.then()
里面的值是NOTaPromise
!!它是promise返回的值:
const promoise = axios.request({
method: 'POST',
url: 'https://api.call'
})
.then(function (response) {
const result = response.data.url;
return result;
})
因此,您一直在向promises
数组推送完全错误的东西!你一直在推送api调用返回的URL字符串,而不是承诺。
让你的代码正常工作是非常简单的:
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)
}
//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
})
// 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!"));