我有一个看起来像这样的代码:
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));
});
我是否在另一个承诺中使用了一个承诺(在这种情况下,这种情况被认为是反模式)?
答案 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
})