【问题标题】:What the right way to use Promises with mongoose?将 Promises 与猫鼬一起使用的正确方法是什么?
【发布时间】:2018-04-15 14:23:17
【问题描述】:

我是 Promises 的新手,两天内我已经看到了至少五种方法。

有些方式是旧版本,有些则专注于其他语言,所以我决定问一下今天应该使用什么。

我是这样做的,带有 'err' 和 'doc' 参数:

Proposals.findById({ ...body, user }, (err, doc) => 
    Advertisements.findOneAndUpdate(
        {_id:  body.advertisement}, {$push: {proposals: doc._id}}
    )
)
.then((Proposals) => Proposals.view())
.then(success(res, 201))
.catch(next)

还有这个:

Proposals.create({ ...body, user })
.then((Proposals) => {
    Advertisements.findOneAndUpdate(
        {_id:  body.advertisement}, {$push: {proposals: Proposals._id}}
    )
    .catch(Advertisements)

    return Proposals.view()
}) 
.then(success(res, 201))
.catch(next)

没有“catch”和“return”是行不通的,但我不知道究竟是为什么。 :x

答案 Using Promises in Mongoose Routes 看起来很漂亮,但我无法在上面的代码中重现。

return findUser(userId)
  .then((user) => findReceipt(user.bookName))
  .then((receipt) => res.status(200).json(receipt))
  .catch((err) => res.status(500).json(null))

这些代码是否更正确? 你能帮我修复第二个代码吗?

谢谢。

【问题讨论】:

  • 到底是怎么回事?您是否收到任何返回的错误消息或您期望它的行为方式?

标签: javascript node.js mongodb mongoose promise


【解决方案1】:

让我详细说明第一块代码的语法:

Proposals.findById({ ...body, user }, (err, doc) => {
  return Advertisements.findOneAndUpdate(
    {_id:  body.advertisement}, {$push: {proposals: doc._id}}
  );
})
.then((Proposals) => { return Proposals.view() })
.then(success(res, 201))
.catch(next)

在 ES6 语法中,这个函数:

() => ('test');

等于

() => { return 'test' };

所以我相信你的主要问题是因为一开始没有完全理解 ES6 语法。

对于Promises,您应该遵循这些最佳做法:

  1. 避免在Promises 中嵌套catch
  2. 通过返回它们链接Promises 并在then 中使用它们

希望对你有帮助。

【讨论】:

  • 你错了,第二个promise块不返回Proposals而是一个广告
  • 感谢您的提示。我改变了你的例子,我让它像这样工作:export const create = ({ user, bodymen: { body } }, res, next) => Proposals.create({ ...body, user }) .then((Proposal) => { return Advertisements.findOneAndUpdate( {_id: body.advertisement}, {$push: {proposals: Proposal._id}} ) .then((Advertisement) => Proposal.view()) }) .then(success(res, 201)) .catch(next)
【解决方案2】:

示例代码没有等待或使用更新的结果。

在 Promise 中 return 使用 Promise 并使用 .then 等待异步操作。然后,您可以根据需要检查结果:

Proposals.create({ ...body, user })
.then((proposal) => {
    return Advertisements.findOneAndUpdate(
        {_id:  body.advertisement}, {$push: {proposals: proposal._id}}
    )
}) 
.then((update) => {
  if (!update) throw new Error(`Could not find advertisement for "${user}"`)
  success(res, 201))
})
.catch(next)

或者等效的 ES2017 代码使用 await 来等待 Promise 解决,这应该有助于解释上述 Promise .then 代码流是如何工作的。

async function handler(){
  try {
    let proposal = await Proposals.create({ ...body, user })
    let update = await Advertisements.findOneAndUpdate(
      {_id:  body.advertisement}, {$push: {proposals: proposal._id}}
    )
    if (!update) throw new Error(`Could not find advertisement for "${user}"`)
    success(res, 201)
  }
  catch (err) {
    next(err)
  }
}

【讨论】:

  • 在第二个例子中你没有使用 Promises,对吧?
  • 第二个例子也是基于 Promise 的。 await 等待承诺解决后再继续
【解决方案3】:

在 Mongoose 中有多种处理承诺的方法。您决定实施它的确切方式取决于个人喜好,但您需要确保您的执行顺序符合预期。在您的第一个示例中,您将回调与承诺混合在一起,我个人认为这不是最佳选择。第三个示例更简洁,因为它是通过then 调用传递的一系列承诺。

需要注意的重要一点是,如果您想在 then 调用中运行异步代码,您需要确保返回一个在正确时刻解析的 Promise。在您的第二个示例中,您可能在您的 findOneAndUpdate 调用完成执行之前返回。您可以通过多种方式避免这种情况。一种选择是将第二个调用包装在Promise 中。我通过混合第二个和第三个示例的部分内容并假设proposal.view() 的返回值不是异步的,在下面给你一个想法。为了清楚起见,我使用明确的 return 语句。

Proposals.create({ ...body, user })
  .then((proposal) => {
    // call returns a new promise
    return new Promise((resolve, reject) => {
      // make second async call to database
      Advertisements.findOneAndUpdate(
        { _id:  body.advertisement }, 
        { $push: { proposals: proposal._id } },
      )
      .then(() => {
        // promise resolves here and passes return
        // value of proposal.view() to next `then`
        return resolve(proposal.view())
      });
    });
  })
  // consume the value from proposal.view() and send it in response
  .then(proposal => res.status(200).json(proposal))
  .catch(next)

这意味着proposal.view() 的返回值只会在findOneAndUpdate 调用完成后传递给下一个then。

【讨论】:

  • 感谢您的解释。在我看来,“findOneAndUpdate”在开始时没有返回是行不通的。对吗?
  • 如果你不返回它或者将它包装在一个返回的promise中,下一个then将执行而不等待findOneAndUpdate返回。这意味着您的res 不会传递findOneAndUpdate 的结果,因此不会返回文档,但数据库中可能会发生更新。返回它会使下一个then 等待承诺在执行之前解决。
猜你喜欢
  • 2019-10-19
  • 2016-12-12
  • 2018-04-10
  • 2013-01-02
  • 1970-01-01
  • 2020-08-27
  • 2020-07-10
  • 2020-09-29
  • 1970-01-01
相关资源
最近更新 更多