在另一个诺言中使用诺言是否被视为反模式?

时间:2019-03-18 10:45:47

标签: javascript promise

我有一个看起来像这样的代码:

app.post("/api/exercise/add", function(req, res, next) {
User
 .findById(req.body.userId)
 .exec()
 .then(user => user)
 .then(function(user) {
   let exercise = new Exercise({
     description: req.body.description,
     duration: req.body.duration,
     date: req.body.date, //BUG: must add validations, date accepts 19984-01-01
     user: user
   })
   .save()
   .then(function(exercise) {
     user.exercises.push(exercise)
     user.
      save().
      then(user => res.json({ status: 201, exercises: user.exercises }))
  })
  .catch(err => next(err))
})
.catch(err => next(err));
});

我是否在另一个承诺中使用了一个承诺(在这种情况下,这种情况被认为是反模式)?

4 个答案:

答案 0 :(得分:3)

从某种意义上讲,它是不雅的-问题是它会创建不必要的.then嵌套。如果遵循这两个承诺的.then.catch处理程序相同,则可以return.then将新的Promise传递到下一个{{1} }或.then,如以下代码所示。

要在不重新分配外部变量的情况下将多个变量/承诺传递给下一个.catch,请使用.then

Promise.all

请注意

app.post("/api/exercise/add", function(req, res, next) {
User
 .findById(req.body.userId)
 .exec()
 .then(function(user) {
   // return the Promise so it can be used by the next then, without nesting
   // because you also need access to `user` in the next then, use Promise.all
   return Promise.all([user, new Exercise({
     description: req.body.description,
     duration: req.body.duration,
     date: req.body.date, //BUG: must add validations, date accepts 19984-01-01
     user: user
   })
   .save()]);
  })
  .then(function([user, exercise]) {
     user.exercises.push(exercise);
     // return the Promise so it can be used by the next then, without nesting:
     return user.save();
   })
   .then(user => res.json({ status: 201, exercises: user.exercises }))
   .catch(err => next(err));
});

完全是多余的-它什么也没做,您已经有了一个承诺,可以在下一个.then(user => user)` 中解析为您想要的user

答案 1 :(得分:1)

我们可以有这样的东西:

new Promise((resolve, reject) => { 
  let x = 25; 
  if (x%2 === 0) {
    return Promise.resolve('even');
  } else {
    return Promise.resolve('odd');
  }
})
.then(result => {
  console.log('the number is '+result);
});

在这种情况下,条件的两个分支都是同构的,它们都返回一个字符串,并且以相同的方式处理结果。

但这并不总是发生,例如:

new Promise((resolve, reject) => {
  if (user.type === 'admin') {
    return this.userService.getAdminTools();
  } else {
    return this.userService.getUserTools();
  }
})
.then(result => {
  // What type is the result? Maybe in this case, chaining is not the best solution! 
});

如果您有更多的分支并且结果不均匀,则链接不是最佳选择。您可以在另一个Promise中监听Promise,也可以只调用另一个包含异步代码的方法

答案 2 :(得分:1)

您的执行流现在分为多个分支,这可能是需要的行为。

在编写代码时,您应该始终考虑可重用性和可读性。

其他程序员如何轻松地阅读和理解我的代码而又不会感到头疼?

将其组合在一起的方式很难遵循。您应该将要执行的异步操作放入单独的函数中。

将复杂的东西分解成函数通常是一种好习惯,不仅在这种情况下也是如此。尝试让一个函数完成一件事情,并拥有一个执行流程。

User
 .findById(req.body.userId)
 .exec()
 .then(user => user)
 .then(user => asynchronousAddUser(user))
 .catch(err => next(err));

答案 3 :(得分:1)

它不一定是反模式,但在很大程度上取决于您为什么这样做。

打破链条并开始新的链条可能是有正当的理由,但是如果您发现自己这样做太频繁,那说明出了点问题,您可能应该重新考虑一下流程。

我看到人们倾向于建立新连锁店的两个常见原因

1。链中某个时刻的处理程序根据条件做出决策,每个分支的工作方式完全不同。在这一点上,开始一个新的链是完全有效的,但是我会创建一个新的方法来返回一个promise。链中的下一个处理程序必须意识到它可能会接收异构数据的事实

NewPromise()
.then( res => {
  if (someCond) {
    return OtherPromise(args)
  }
  ....
  return obj
})
.then( res => {
  //this promise must be aware that res may be heterogeneous
})

2。在链中,处理程序会收到一些您不容易在链中向下传播的信息。例如,当需要两个来自数据库的不同信息时,最后都需要两者来完成工作。

User.findById(uid1)
.then(user1 => {
  return User.finById(uid2)
})
.then(user2 => {
 // at this point user1 is not available any more
})

对此的一种解决方案是在链外具有变量,而不是开始新的链

var user1

User.findById(uid1)
.then(user => {
  user1 = user
  return User.finById(uid2)
})
.then(user2 => {
 // at this point user is available and has the value of user1
})