【问题标题】:Using mongoose promises with async/await使用带有 async/await 的 mongoose 承诺
【发布时间】:2018-03-09 11:37:50
【问题描述】:

我正在尝试将 Mongoose Promise 与 Node.js 的 async/await 功能结合使用。当我的函数printEmployees 被调用时,我想保存orderEmployees 函数查询的员工列表。而orderEmployees 中的console.log 语句返回了预期的查询,printEmployees 中的console.log 返回了undefined,这表明我没有正确返回承诺。

我完全不熟悉承诺,以至于我没有正确理解范式......非常感谢任何帮助。

  printEmployees: async(company) => {
    var employees = await self.orderEmployees(company);
    // SECOND CONSOLE.LOG
    console.log(employees);
  },

  orderEmployees: (companyID) => {
    User.find({company:companyID})
    .exec()
    .then((employees) => {
      // FIRST CONSOLE.LOG
      console.log(employees);
      return employees;
    })
    .catch((err) => {
      return 'error occured';
    });
  },

【问题讨论】:

    标签: javascript node.js asynchronous promise


    【解决方案1】:

    为了使orderEmployees 表现得像异步函数,您必须返回结果承诺。使用不带 async/await 关键字的 Promise 时需要遵循两条规则:

    1. 如果函数返回Promise,则该函数是异步的
    2. 如果您有一个承诺(例如由异步函数返回),则必须对其调用 .then 或将其返回。

    当您使用 async/await 时,您必须 await 兑现您获得的承诺。

    这表示你会注意到你没有返回在orderEmployees 中生成的承诺。很容易修复,但也很容易将该函数重写为异步。

    orderEmployees: (companyID) => {
      return User.find({company:companyID}) // Notice the return here
      .exec()
      .then((employees) => {
        // FIRST CONSOLE.LOG
        console.log(employees);
        return employees;
      })
      .catch((err) => {
        return 'error occured';
      });
    },
    

    或

    orderEmployees: async(companyID) => {
      try {
        const employees = await User.find({company:companyID}).exec();
        console.log(employees);
        return employees;
      } catch (err) {
        return 'error occured';
      }
    },
    

    PS:这里的错误处理有些缺陷。我们通常不会通过从函数返回错误字符串来处理错误。在这种情况下,最好让错误传播,并从一些顶级 UI 代码中处理它。

    【讨论】:

    • 嗨,你能做 async(companyID) => { await User.find({company:companyID}).then(data =>{ return data }).catch(err => { return err .message }) }
    • @ODaneBrissett 到底是什么问题?你写的代码有很多问题,它不会工作。从技术上讲,您可以将 await 和 then 混合使用,但我建议您不要这样做,因为它很容易出错。只需使用异步等待。 try { return await User.find(); } catch(e) { showerror(e.message); // dont return the error message, you never want to do that }
    • 我只是在寻求澄清,看看我的方法是否可行。但感谢您的意见。你能说为什么它不起作用
    • @O'DaneBrissett 我注意到 4 件事,1:异步函数没有返回任何东西 2:.then(data =>{ return data }) 没有做任何事情,它只是评估为具有相同分辨率值的类似承诺, 3:.catch(err => { return err.message }) 将隐藏异常,使处理错误变得不可能,4:一个危险信号是异步函数中没有等待
    • 嗯,这很有趣,但是,这是我下面的完整实现,它可以工作 exports.getLoan = async (req, res) => { await Loans.findById(req.params.id) .then(data => { if (!data) return res.status(404).send('Sponsored product not found') res.send(data) }) .catch(err => { return res.status(500).send({ message: err.message }) }) } 只是控制器中的一种方法。我进行了测试,它捕获了错误并返回了响应。我只是想知道这种方法是否有任何错误
    【解决方案2】:

    你需要return你的Promise。

    • 目前,您正在等待返回 undefined 的函数。
    • await 仅在与 Promise 一起使用时才真正“等待”该值。
    • 始终牢记you can only await Promises 或async functions,它们隐式返回Promise1。

    orderEmployees: (companyID) => {
      return User.find({ company:companyID }).exec()
    }
    

    同样重要的是,您应该在 .catch 处理程序中使用 throw 而不是 return。从.catch 处理程序中返回将导致承诺链触发它的.then 而不是.catch,从而破坏错误处理链。

    更好的是,根本不要包含.catch,让实际错误在承诺链中冒泡,而不是用您自己的非描述性'error occured' 消息覆盖它。

    错误条件应该抛出错误,而不是返回它。


    1 您也可以等待非 Promise,但仅限于同步评估的值。

    【讨论】:

      【解决方案3】:

      您没有从 orderEmployees 返回 Promise。

      printEmployees: async(company) => {
        var employees = await self.orderEmployees(company);
        // SECOND CONSOLE.LOG
        console.log(employees);
      },
      
      orderEmployees: (companyID) => {
        return User.find({company:companyID})
       .exec()
       .then((employees) => {
         // FIRST CONSOLE.LOG
         console.log(employees);
         return employees;
       })
       .catch((err) => {
         return 'error occured';
       });
      },
      

      【讨论】:

        【解决方案4】:

        你需要从orderEmployees返回一个Promise

        orderEmployees: companyId => User.find({ companyId }).exec()
        

        如果您想在返回之前进行一些错误处理或预处理,那么您可以保持您的代码不变,但请记住返回结果(promise 是可链接的)。

        【讨论】:

        • 我看不出explicit promise creation antipattern 将如何帮助处理错误。有什么好处?你可以从一个简单的异步函数中获取return employees 和throw e。
        • @TamasHegedus 是的,好点,Node 不能很好地处理从内部承诺抛出异常的旧习惯!
        【解决方案5】:

        如果您要使用 async/await,那么它的工作原理是这样的。

        • 在返回承诺的函数前面等待。
        • async 在包装函数前面。
        • 将函数体包装在 try/catch 块中。

        请看一下这个函数,它是一个中间件 在我在 express 中执行特定路线之前。

        const validateUserInDB = async (req, res, next) => {
            try {
                const user = await UserModel.findById(req.user._id);
                if (!user) return res.status(401).json({ message: "Unauthorized." });
                req.user = user;
                return next();
            } catch (error) {
                return res.status(500).json({ message: "Internal server error." })
            }
        }
        
        • await 之后的代码正在等待 promise 被解析。
        • catch 块会捕获 try 块内发生的任何错误,即使 catch 方法触发的错误来自等待 promise。

        【讨论】:

          猜你喜欢
          • 2021-06-29
          • 1970-01-01
          • 1970-01-01
          • 2016-02-02
          • 1970-01-01
          • 1970-01-01
          • 2021-11-27
          • 2016-05-20
          相关资源
          最近更新 更多