【问题标题】:Chaining ES6 promises without nesting在没有嵌套的情况下链接 ES6 Promise
【发布时间】:2017-08-04 10:05:32
【问题描述】:

我试图在第一个 then 方法之后链接第二个 then 方法,但由于某种原因它无法正常工作。只有当我嵌套 then 方法时它才能正常工作。以下是无法正常工作的代码:

auth.post('/signup', (req, res, next) => {

  const { username } = req.body
  const { password } = req.body

  Users.findOne({ username })
    .then(
      existingUser => {
        if (existingUser) return res.status(422).send({ error: 'Username is in use' })

        const user = new Users({ username, password })
        user.save()
      },
      err => next(err)
    )
    .then(
      savedUser => res.send({ 
        username: savedUser.username, 
        password: savedUser.password 
      }),
      err => next(err)
    )
})

在这里,当我向'/signup' 发帖时,user 被保存到数据库中,但我没有得到包含用户名和密码的响应。然而:

auth.post('/signup', (req, res, next) => {

  const { username } = req.body
  const { password } = req.body

  Users.findOne({ username })
    .then(
      existingUser => {
        if (existingUser) return res.status(422).send({ error: 'Username is in use' })

        const user = new Users({ username, password })
        user.save()
        .then(
          savedUser => res.json({ 
            username: savedUser.username,
            password: savedUser.password
          }),
          err => next(err)
        )
      },
      err => next(err)
    )
})

这按预期工作。 user 被保存,我得到用户名和密码的响应。我读过您可以以扁平方式链接这些 then 方法而无需嵌套。但是我在这里检查了问题,但找不到关于我在这里做错了什么的答案。有人可以帮忙解决这个问题吗?

【问题讨论】:

  • 更改了我的答案以尽可能地帮助您,希望对您有所帮助;)
  • 是的。还要感谢猫鼬脚注。我已经有一段时间没有使用猫鼬了。
  • Conditions require nesting。没有出路,也没有错。

标签: javascript ecmascript-6 es6-promise


【解决方案1】:

简单的三步流程:

  1. 从第一个 .then 调用返回一个承诺。

改变这个:

// ...
const user = new Users({ username, password })
user.save()
// ...

到这里:

// ...
const user = new Users({ username, password })
return user.save()
// ...

(注意 return 关键字,它将与第二个 .then() 调用链接)


2。如果existingUser返回false,则拒绝Promise(感谢@JaromandaX指出)

改变这个:

if (existingUser) return res.status(422).send({ error: 'Username is in use' })

到这里:

if (existingUser) {
    res.status(422).send({ error: 'Username is in use' });
    return Promise.reject('USER_EXISTS');
}

3.尽可能删除 .then(onResolvedFunction, onRejectedFunction) 模式,并改用 .catch(err)(以捕获更大范围的错误)。

从您的.then() 中删除第二个参数

,
err => next(err)

使用 .catch 代替:

Users.findOne({ username })
    .then(...)
    .then(...)
    .catch((e) => { // <-- Handle the error properly
         console.log(e);
         if (e !== 'USER_EXISTS')
             next(err);
     }); 

猫鼬脚注!

这与承诺无关。我看到您将模型命名为 Users,但请记住,在内部,Mongoose 会为您的模型名称复数。您应该:

  • 将您的模型命名为User;或

  • 在第三个参数中显式设置复数形式,如下所示:

    const Users = mongoose.model('User', UserSchema, 'Users');

【讨论】:

  • 这里唯一的问题是 then( savedUser =&gt; res.send(... 代码即使在 existingUser 是 true 的情况下也会运行 - 可能不是 OP 想要的......同样在 @ 被拒绝的情况下987654340@ 链接的.then 也将被执行
  • OP 在他的.thens 中使用.then(onResolvedFunction, onRejectedFunction) 模式——同样,在现有用户的情况下,您的代码将执行next(err),原始代码不会
【解决方案2】:

您的“链式”版本至少存在三个问题

  1. 你没有从你的第一个.then返回任何东西
  2. 在现有用户的情况下,链接的.then 仍将被执行
  3. 如果Users.findOne 被拒绝,链接的.then 也将被执行

修复:

  1. 直接返回.save()
  2. 返回一个Promise.reject - 或者你可以throw 一个错误
  3. 不要在.then 中使用onRejected 函数,只需在链的末尾有一个拒绝处理程序,在.catch 中

我会像这样链接该代码:

auth.post('/signup', (req, res, next) => {

    const { username } = req.body
    const { password } = req.body

    Users.findOne({ username })
    .then(existingUser => {
        if (existingUser) {
            return Promise.reject({
                status:422,
                error: 'Username is in use' 
            });
        }
        return new Users({ username, password }).save();
    })
    .then(savedUser => res.send({ 
        username: savedUser.username, 
        password: savedUser.password 
    }))
    .catch(err => {
        if (err.status) {
            return res.status(err.status).send({ error: err.error });
        }
        return next(err);
    });
});

【讨论】:

  • 我相应地修改了我的答案。你认为有必要添加第二个答案吗?
  • 是的,因为此代码在所有情况下都表现得与原始代码一样,所以在现有用户的情况下您的代码不会 - 即您的代码仍会调用 next(err),原始代码不会
  • 修改它以最大化OP对问题的理解。请注意我在答案中付出了多少努力!祝您有美好的一天,感谢您指出我忽略的错误。
  • 我的回答只考虑了几秒钟。如有不足之处欢迎指出
  • @JoseLopezGarcia - 你想让我让 OP 接受你的回答吗?我不会发布分数的答案,但如果它对你很重要,你可以拥有 15
猜你喜欢
  • 1970-01-01
  • 2020-01-12
  • 1970-01-01
  • 2013-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
  • 2014-07-09
相关资源
最近更新 更多