等待Promise.all继续执行

时间:2019-12-27 11:11:42

标签: javascript promise

我想将产品插入数组,然后继续使用该数组。我没有使用Promisses的经验。贝娄是我的代码。 这是我想返回数组的函数。

const findProduct = async function(request) {
  const products = [];

  await Promise.all(
    request.products.forEach(async product => {
      await db
        .get()
        .collection('products')
        .findOne({ _id: product.productId.toString() }, (err, result) => {
          if (err) throw new Error('exception!');
          products.push(result);
        });
    })
  )
    .then(() => {
      return products;
    })
    .catch(e => e);
};

产品始终是不确定的。

我应该返回Promise。所有我都将其保存到一个数组中,然后使用该数组吗?

这就是我打算使用数组的方式

const purchase = new Purchase(req.body);

const products = await findProduct(req.body);
purchase.products = [...products];

2 个答案:

答案 0 :(得分:2)

findProduct函数的上下文中,如果打算等待使用async的结果,则使用await / findProduct语法没有多大意义const products = await findProduct(req.body);

相反,您只想使用Promises来定义函数。

首先,db.collection.findOne()使用异步事件的回调,要在Promise链中使用此回调,必须将其包装在Promise中。可以这样做:

new Promise((resolve, reject) => {
  db
    .get()
    .collection('products')
    .findOne({ _id: product.productId.toString() }, (err, result) => { err ? reject(err) : resolve(result) })
});

(err, result) => { err ? reject(err) : resolve(result) }只是

的简明形式
(err, result) => {
  if (err) {
    reject(err);
  } else {
    resolve(result);
  }
}

接下来,您必须将数组传递给Promise.all()。因为您已经有了数组request.products,所以您可以将每个值转换(或映射)为其对应的Promise以获取其数据。这是使用Array.prototype.map完成的。以这种方式使用时,Promise.all()将以与request.products相同的顺序解析为一系列产品数据对象。

将其混合到您的代码中,将产生:

const findProduct = function(request) {
  return Promise.all(
    request.products.map(product => {
      return new Promise((resolve, reject) => {
        db
          .get()
          .collection('products')
          .findOne({ _id: product.productId.toString() }, (err, result) => err ? reject(err) : resolve(result))
      });
    })
  );
};

请注意,我删除了.then(()=>products)(因为Promise.all会根据上述承诺返回产品本身)和.catch(e=>e)(因为您不应忽略这样的错误)。

有了这些更改,您现在可以像在问题中一样使用findProduct


更新

似乎MongoDB API符合Promises,这意味着我们可以删除Promise回调包装并将其简化为:

const findProduct = function(request) {
  return Promise.all(
    request.products.map(product => {
      return db
        .get()
        .collection('products')
        .findOne({ _id: product.productId.toString() });
    })
  );
};

答案 1 :(得分:0)

Promise.all()期望一个Promises数组,而map将返回一个数组。由于db也将返回一个Promise,因此我们只将这些承诺提供给Promise.all()

编辑:忘记返回Promise.all()并返回一个保证,因此可以与await findproducts()findproducts().then()一起使用

const findProduct = function (request) {

return Promise.all(
    request.products.map(product => {
        return db
            .get()
            .collection('products')
            .findOne({ _id: product.productId.toString() }
            });
    })
)};

由于很多人问:“我如何从Promise中得到一些东西?” ->使用解析值


这里有一个很长的解释,它为什么起作用:wait()将返回一个Promise,该承诺将通过map()映射到一个数组中,并返回该数组。因此,完成映射后,我们将获得一个数组,其中包含3个wait()调用返回的3个Promises。该数组传递到Promise.all()中,它将等待所有Promises解析,并将其自身解析为具有该数组中Promises的所有解析值的数组。由于findProduct()将在Promise.all()findProduct().then()

访问时从await findProduct()返回此承诺。
const start = { products: ['milk', 'butter', 'eggs'] }

const findProduct = function (request) {
    return Promise.all(
        request.products.map(product => {
            return wait(product)
        })
    )
};

function wait(product) {
    return new Promise((resolve) => {
        setTimeout(() => { resolve(product) }, 5000)
    })
}

findProduct(start).then(res => console.log(res))
// logs [ 'milk', 'butter', 'eggs' ]

编辑:要回答有关.then()返回承诺的评论

findProduct(start)
.then(res => console.log(res))
.then(res => console.log(res))
// logs [ 'milk', 'butter', 'eggs' ] and undefined

findProduct(start)
.then(res => {console.log(res); return res})
.then(res => console.log(res))
// logs 2x [ 'milk', 'butter', 'eggs' ]