#javascript #node.js #asynchronous #async-await
Вопрос:
Я уже некоторое время пытаюсь понять, что в этом не так, но все еще не могу понять, что я делаю не так. Я пытаюсь добавить в базу данных каждый элемент корзины пользователя в качестве элемента заказа с помощью функции .map () (элемент заказа в базе данных соответствует продукту, который на самом деле не имеет отношения к вопросу, но помогает, если вы пытаетесь понять операцию) :
const orderItems= orderData.map(async product=>{
const productId=product.id.slice(0,product.id.length-5)
const targetProduct=await dataSources.ProductAPI.product(productId)
const name=targetProduct.name
const quantity=218327
await dataSources.OrderItemAPI.createOrderItem(orderId,productId,name,quantity,{ttlInSeconds:60*20})
})
Затем я пытаюсь сопоставить каждый элемент заказа из приведенного выше массива orderItems
с реальным продуктом в базе данных, например:
//мы находим продукт, соответствующий каждому элементу заказа
const productsCorrespondingToOrderItems= orderItems.map(async orderItem=>{
const trial=await orderItem
console.log(trial) <--- returns undefined
// OR just logging orderItem returns a promise
await dataSources.TransactionAPI.findProductFromOrderItem(orderItem.productId).then(x=>console.log(x))
})
Я проверил каждый товар из пунктов заказа, и все выглядит нормально. Проблема в том, что каждый orderItem
из productsCorrespondingToOrderItems
них возвращает восьмое обещание , когда я просто регистрирую его, или не определено, жду ли я его. Я действительно не понимаю, что я делаю не так? Большое вам спасибо !
Комментарии:
1. Вы ничего не возвращаете со своих
map()
обратных вызовов2. @RobbyCornelissen Большое спасибо за быстрый ответ ! Я не знаю, как я это пропустил, попробую прямо сейчас !
3. То, что вы пытаетесь сделать, не имеет большого смысла.
Array.map
не работает с асинхронным кодом.Array.map
предназначен только для синхронного кода. Если вы хотите выполнять последовательные циклы, используяasync/await
, вы должны использоватьfor
for ... of
циклы or. Если вы хотите выполнять параллельные асинхронные операции, вы должны создавать свои обещания, используяArray.map
их, а затем использоватьPromise.all
для их ожидания.4. @nicholaswmin — Для нас очень часто
map
приasync
обратном вызове создается массив обещаний, которые вы затем ждете (например, с помощьюPromise.all
или одним из других методов комбинатора обещаний).5. @T. J. Краудер Да, действительно, но я уже упоминал об этом в последней части своего комментария.
Ответ №1:
async
функции всегда возвращают обещание. Вы ничего не возвращаете из своих map
обратных вызовов, поэтому, поскольку обратные вызовы являются async
функциями, они возвращают обещания, которые выполняются undefined
.
Если вы хотите дождаться выполнения всех обещаний, данных в ходе ваших map
операций, используйте Promise.all
результат. Promise.all
возвращает обещание, которое будет выполнено с массивом значений выполнения данных вами обещаний (если все они выполнены) или отклонено при первом отклонении любого из них. Вы ждете этого обещания либо с await
помощью (в async
функции), либо с помощью вызова .then
/ .catch
по нему.
Вот пример, в котором предполагается, что код, в котором вы выполняете, map
не находится в async
функции:
// If not in an `async` function
Promise.all(orderData.map(async product => {
const productId = product.id.slice(0, product.id.length - 5);
const targetProduct = await dataSources.ProductAPI.product(productId);
const name = targetProduct.name;
const quantity = 218327;
const orderItem await dataSources.OrderItemAPI.createOrderItem(
orderId,
productId,
name,
quantity,
{ ttlInSeconds: 60 * 20 }
);
return await dataSources.TransactionAPI.findProductFromOrderItem(orderItem.productId);
}))
.then(productsCorrespondingToOrderItems => {
// ...use `productsCorrespondingToOrderItems` here...
})
.catch(error => {
// ...handle/report error...
});
Обратите внимание, что это делает работу параллельно. Если вы хотите делать это последовательно, используйте async
функцию и for-of
цикл.
Ответ №2:
Вы ничего не вернули со своей карты, и карта не работает для асинхронного/ожидания. Сделайте это вместо того, чтобы вызывать api один раз за раз (последовательно). Если вы хотите ожидать несколько вызовов api одновременно (параллельно), используйте ответ от TJ Crowder.
const orderItems= [];
for (const product of orderData) {
const productId=product.id.slice(0,product.id.length-5)
const targetProduct=await dataSources.ProductAPI.product(productId)
const name=targetProduct.name
const quantity=218327
await dataSources.OrderItemAPI.createOrderItem(orderId,productId,name,quantity,{ttlInSeconds:60*20})
})
// push something to the orderItems array here!
}
Комментарии:
1. Большое спасибо!!