Javascript 在另一个承诺中使用承诺是否被视为反模式?
我有一个如下代码:Javascript 在另一个承诺中使用承诺是否被视为反模式?,javascript,promise,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.b
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));
});
在本例中,我在另一个允诺中使用允诺这一事实是否被视为反模式?从某种意义上说,这是不雅观的-问题是它创建了不必要的
。然后
嵌套。如果遵循这两个承诺的.then
和.catch
处理程序相同,则只需在中返回新承诺。然后
将其传递到下一个。然后
或catch
,如下代码所示
要将多个变量/承诺传递给下一个。然后
而不重新分配外部变量,请使用承诺。所有
:
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)`
是完全多余的-它没有任何作用,您已经有了一个承诺,可以在下一个中解析为您想要的用户
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!
});
如果您有更多的分支,并且结果不一致,那么链接可能不是最佳选择。您可以在另一个承诺中侦听该承诺,也可以只调用另一个包含异步代码的方法您的执行流现在被分成多个分支,这可能是您想要的行为
在编写代码时,您应该始终考虑可重用性和可读性
其他程序员如何轻松地阅读和理解我的代码而不感到头痛
你把它放在一起的方式很难理解。您应该将要执行的异步操作放入一个单独的函数中
将复杂的东西分解成函数是一种普遍使用的好方法,而不仅仅是在这种特殊情况下。尝试使用一个函数来完成一件事,并使用一个执行流
User
.findById(req.body.userId)
.exec()
.then(user => user)
.then(user => asynchronousAddUser(user))
.catch(err => next(err));
它不一定是一个反模式,但这在很大程度上取决于您为什么要这样做
打破这个链条并开始一个新的,可能有合理的理由,但是如果你发现自己经常这样做,那么事情就错了,也许你应该重新考虑你的流程
我发现人们倾向于建立新连锁店的两个常见原因
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
})
1.处理程序在链中的某个点根据条件做出决策,每个分支都有完全不同的工作方式。在这一点上,启动一个新的链是完全有效的,但是我将创建一个新的方法来返回一个承诺。链中的下一个处理程序必须知道它可能接收异构数据这一事实
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
})
这的确是一种气味。更多的气味是火,当你保存时忘记你正在表演。你应该考虑使用@ SpEnter,我希望在下一个捕捉中会发现最终的错误,或者他们不会吗?如果你<代码>返回用户.SaveE()(用户= > RES.JSON({状态:201,练习:用户。练习}))
然后值/错误将流经承诺链。如果不返回承诺,您将在保存过程中跳过捕获。。然后(函数(练习){user.exerces.push(练习)}
引发“用户未定义”。用户对象似乎不在练习承诺的范围内。我可以在findById
完成时使用一些临时变量来存储用户,然后使用它来推动练习。是否有任何方法来解决此异构返回,使用户在返回练习对象后可用?是的,您可以使用Promise.all
要沿承诺链传递多个值而不创建不必要的外部变量,请参见编辑