Promise.all 几乎就是为这个确切的用例而设计的:
// A dummy "Product" with a dummy "getProductDetails" implementation
// so that we can have a working test example
let Product = {
getProductDetails: (productId, callback) => {
setTimeout(() => {
callback({ type: 'productDetails', productId });
}, 100 + Math.floor(Math.random() * 200));
}
};
// This is the function you're looking for:
let getCompleteCart = async (cart) => {
return Promise.all(cart.products.map(async ({ productId, productCount }) => ({
product: await new Promise(resolve => Product.getProductDetails(productId, resolve)),
productCount
})));
}
let exampleCart = {
products: [
{ productId: 982, productCount: 1 },
{ productId: 237, productCount: 2 },
{ productId: 647, productCount: 5 }
]
};
getCompleteCart(exampleCart).then(console.log);
getCompleteCart的细分:
let getCompleteCart = async (cart) => {
return Promise.all(cart.products.map(async ({ productId, productCount }) => ({
product: await new Promise(resolve => Product.getProductDetails(productId, resolve)),
productCount
})));
}
Promise.all (mdn) 专门用于等待 Promise 数组中的每个 Promise 解决
我们需要向Promise.all 提供一个承诺数组。这意味着我们需要将我们的数据数组 (cart.products) 转换为 Promise 数组; Array.protoype.map 是完美的工具。
提供给cart.products.map 的函数将购物车中的每个产品转换为一个类似于{ product: <product details>, productCount: <###> } 的对象。
这里的棘手之处在于获取“product”属性的值,因为该值是异步的(由回调返回)。以下行创建了一个 Promise,它使用 Promise 构造函数 (mdn) 解析为 Product.getProductDetails 返回的值:
new Promise(resolve => Product.getProductDetails(productId, resolve))
await 关键字允许我们将此承诺转换为它产生的未来值。我们可以将这个未来值分配给“产品”属性,而“产品计数”属性只是从原始项目中复制而来购物车:
{
product: await new Promise(resolve => Product.getProductDetails(productId, resolve)),
productCount
}
为了在正确的时间运行console.log,我们需要等待所有产品详细信息完成编译。幸运的是,这是由getCompleteCart 在内部处理的。我们可以在适当的时候console.log等待getCompleteCart解决。
有两种方法可以做到这一点:
使用Promise.prototype.then (mdn):
getCompleteCart(exampleCart).then(console.log);
或者,如果我们在 async 上下文中,我们可以使用 await:
let results = await getCompleteCart(exampleCart);
console.log(results);