将键添加到异步函数中的对象数组
Add key to array of objects in async function
我有一个 api 路由需要从两个来源获取数据,将数据合并到一个对象中,然后 return。我遇到的问题是我基本上陷入了 async/await 地狱,当推送到 .then()
块中的第二个数组时,第二个数组名为
clone
returns []
。如何发出 api 请求,合并数据并根据需要 return 给请求者?
获取代码:
export default async function getProduct(product_id) {
const product = await fetch(
`${process.env.PRIVATE_APP_URL}/products/${product_id}.json`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then((result) => {
return result.json();
});
return product.product;
}
API 处理程序:
const recharge_subscription_res = await rechargeAPI(
"GET",
`https://api.rechargeapps.com/subscriptions?customer_id=${recharge_customer.id}`
);
const closest_array = recharge_subscription_res.subscriptions.filter(
(e) => e.next_charge_scheduled_at == closest_date
);
let clone = [];
closest_array.forEach((element) => {
getProduct(element.shopify_product_id).then((product) => {
element.shopify_product_handle = product.handle;
element.shopify_product_image_url = product.image.src;
clone.push(element);
});
});
console.log(clone);
clone
应该像 closest_array
一样记录为对象数组,但记录为空数组。这与其他看似重复的问题并不完全相同,因为通常它们的功能不需要将承诺的数据发送回外部源。大多数问题都与事物的前端有关。我的情况是 Express.js API。任何帮助将不胜感激。
您的代码存在缺陷(在下面显示的部分中)。你有一个悬而未决的承诺,你忘了等待或 return。
当您记录 clone
时,none 的异步 getProduct
操作已经完成,并且 none 的元素已被推送。
let clone = [];
closest_array.forEach((element) => {
getProduct(element.shopify_product_id).then((product) => {
element.shopify_product_handle = product.handle;
element.shopify_product_image_url = product.image.src;
clone.push(element);
}); // FLAW: dangling .then
});
console.log(clone); // FLAW: clone is not ready yet.
我会更像这样设置它:
let clone = await Promise.all(closest_array.map((element) =>
getProduct(element.shopify_product_id).then((product) => {
element.shopify_product_handle = product.handle;
element.shopify_product_image_url = product.image.src;
return element;
})
));
console.log(clone);
按照你现在的方式修改 element
有点粗略(我不会),但这样 getProduct
调用会一起进行以实现最大效率。 Promise.all
处理等待所有承诺并将每个结果放入结果数组中,然后您可以将其作为单个承诺等待,因为调用函数是异步的。
原来的 promise 规范使用 .then()
,新语法隐藏了 then's with await。 Style-wise,选择就一种风格是有意义的。
在任何一种风格中,在循环中创建许多 promise 都存在一些挑战。 js 迭代函数(如 map
和 forEach
)采用 synchronous 函数。最常见的设计是在同步循环中创建一组承诺,然后 运行 它们与 Promise.all()
并发。考虑到这两个想法...
您可以(但不必)像这样重写您的网络请求...
// since we decorated "async" let's use await...
export default async function getProduct(product_id) {
const url = `${process.env.PRIVATE_APP_URL}/products/${product_id}.json`;
const options = { method: "GET", headers: { "Content-Type": "application/json" }};
const result = await fetch(url, options);
const product = await result.json();
return product.product;
}
await
不允许出现在 top-level;它只能在异步函数中使用。这里我自己编个名字猜一下参数
async function rechargeAndLookupProduct(recharge_customer) {
const base = 'https://api.rechargeapps.com/subscriptions';
const query = `customer_id=${recharge_customer.id}`;
const recharge_subscription_res = await rechargeAPI("GET",`${base}?${query}`);
const closest_array = recharge_subscription_res.subscriptions.filter(e =>
e.next_charge_scheduled_at == closest_date
);
// here's the important part: collect promises synchronously
// execute them together with Promise.all()
const promises = closest_array.map(element => {
return getProduct(element.shopify_product_id)
});
const allProducts = await Promise.all(promises);
// allProducts will be an array of objects that the promises resolved to
const clones = allProducts.map((product, i) => {
// use Object.assign so we'll really have a "clone"
let closest = Object.assign({}, closest_array[i]);
closest.shopify_product_handle = product.handle;
closest.shopify_product_image_url = product.image.src;
return closest;
});
// if I didn't make any typos (which I probably did), then
// clones ought to contain the result you expect
console.log(clones);
}
我有一个 api 路由需要从两个来源获取数据,将数据合并到一个对象中,然后 return。我遇到的问题是我基本上陷入了 async/await 地狱,当推送到 .then()
块中的第二个数组时,第二个数组名为
clone
returns []
。如何发出 api 请求,合并数据并根据需要 return 给请求者?
获取代码:
export default async function getProduct(product_id) {
const product = await fetch(
`${process.env.PRIVATE_APP_URL}/products/${product_id}.json`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
).then((result) => {
return result.json();
});
return product.product;
}
API 处理程序:
const recharge_subscription_res = await rechargeAPI(
"GET",
`https://api.rechargeapps.com/subscriptions?customer_id=${recharge_customer.id}`
);
const closest_array = recharge_subscription_res.subscriptions.filter(
(e) => e.next_charge_scheduled_at == closest_date
);
let clone = [];
closest_array.forEach((element) => {
getProduct(element.shopify_product_id).then((product) => {
element.shopify_product_handle = product.handle;
element.shopify_product_image_url = product.image.src;
clone.push(element);
});
});
console.log(clone);
clone
应该像 closest_array
一样记录为对象数组,但记录为空数组。这与其他看似重复的问题并不完全相同,因为通常它们的功能不需要将承诺的数据发送回外部源。大多数问题都与事物的前端有关。我的情况是 Express.js API。任何帮助将不胜感激。
您的代码存在缺陷(在下面显示的部分中)。你有一个悬而未决的承诺,你忘了等待或 return。
当您记录 clone
时,none 的异步 getProduct
操作已经完成,并且 none 的元素已被推送。
let clone = [];
closest_array.forEach((element) => {
getProduct(element.shopify_product_id).then((product) => {
element.shopify_product_handle = product.handle;
element.shopify_product_image_url = product.image.src;
clone.push(element);
}); // FLAW: dangling .then
});
console.log(clone); // FLAW: clone is not ready yet.
我会更像这样设置它:
let clone = await Promise.all(closest_array.map((element) =>
getProduct(element.shopify_product_id).then((product) => {
element.shopify_product_handle = product.handle;
element.shopify_product_image_url = product.image.src;
return element;
})
));
console.log(clone);
按照你现在的方式修改 element
有点粗略(我不会),但这样 getProduct
调用会一起进行以实现最大效率。 Promise.all
处理等待所有承诺并将每个结果放入结果数组中,然后您可以将其作为单个承诺等待,因为调用函数是异步的。
原来的 promise 规范使用 .then()
,新语法隐藏了 then's with await。 Style-wise,选择就一种风格是有意义的。
在任何一种风格中,在循环中创建许多 promise 都存在一些挑战。 js 迭代函数(如 map
和 forEach
)采用 synchronous 函数。最常见的设计是在同步循环中创建一组承诺,然后 运行 它们与 Promise.all()
并发。考虑到这两个想法...
您可以(但不必)像这样重写您的网络请求...
// since we decorated "async" let's use await...
export default async function getProduct(product_id) {
const url = `${process.env.PRIVATE_APP_URL}/products/${product_id}.json`;
const options = { method: "GET", headers: { "Content-Type": "application/json" }};
const result = await fetch(url, options);
const product = await result.json();
return product.product;
}
await
不允许出现在 top-level;它只能在异步函数中使用。这里我自己编个名字猜一下参数
async function rechargeAndLookupProduct(recharge_customer) {
const base = 'https://api.rechargeapps.com/subscriptions';
const query = `customer_id=${recharge_customer.id}`;
const recharge_subscription_res = await rechargeAPI("GET",`${base}?${query}`);
const closest_array = recharge_subscription_res.subscriptions.filter(e =>
e.next_charge_scheduled_at == closest_date
);
// here's the important part: collect promises synchronously
// execute them together with Promise.all()
const promises = closest_array.map(element => {
return getProduct(element.shopify_product_id)
});
const allProducts = await Promise.all(promises);
// allProducts will be an array of objects that the promises resolved to
const clones = allProducts.map((product, i) => {
// use Object.assign so we'll really have a "clone"
let closest = Object.assign({}, closest_array[i]);
closest.shopify_product_handle = product.handle;
closest.shopify_product_image_url = product.image.src;
return closest;
});
// if I didn't make any typos (which I probably did), then
// clones ought to contain the result you expect
console.log(clones);
}