previous post建议我避免参考following question in stackoverflow
的显式Promise构造反模式。坦白说,我是JS和node的新手,并且我并没有经常使用promise。我去看了那些文章,但要么我无法理解或无法联系,要么我对诺言的理解一直含糊不清
因此,我决定在一个新线程中询问此问题并寻求帮助。
我正在创建帮助程序/通用函数,可以用来使代码保持整洁,如果万一我想随时更改函数内部的任何内容,则不必手动更改每个函数。
这些是我已经完成的功能
//Find user by email Address
const findUserByEmail = (emailAddress) => {
return new Promise((resolve, reject) => {
User.findOne({email: emailAddress}).then(response => {
resolve(res)
}).catch(error => {
reject("Error in findUserByEmail", error);
})
})
}
//Create User
const createNewUser = (newUserDetails) => {
return new Promise((resolve, reject) => {
new User({
fullName: newUserDetails.fullName,
email: newUserDetails.email,
image: newUserDetails.image,
gender: newUserDetails.gender,
age: newUserDetails.age
}).save().then((response) => {
resolve(response)
}).catch((error) => {
reject("Problem in Creating New User", error)
})
})
}
现在,我假设SomePerformance表示对诺言的过度使用,因为当我已经在猫鼬return new Promise((resolve, reject) => {
中使用诺言时,我正在创建新的诺言User.findOne({email: emailAddress}).then(response => {
吗?
但是我创建这些承诺的原因是,当我在导入后从应用程序中的任何位置调用这些帮助程序功能
const { findUserByEmail } = require("./my_db_query");
我可能希望它返回响应或在出现错误的情况下抛出错误
findUserByEmail("test@example.com").then(/*...*/).catch(/*...*/);
如果我在不添加新承诺的情况下更改了上述代码段
function findUserByEmail (email) {
return User.findOne({email: email}).then(currentUser => currentUser).catch(error => error)
}
然后我可能无法在.then
中的.catch
和findUserByEmail("test@example.com")
?
在App的API路由中,我将调用findUserByEmail("test@example.com")
函数,如果发生错误,我想做其他事情(不同情况下会有所不同,因此我无法在其中使用它我的助手功能)。
是的,现在做return new Promise((resolve, reject) => {
而不是只做一个return User.findOne(
还是有意义的吗?
答案 0 :(得分:4)
由于.findOne
已经返回了Promise
,因此无需使用new Promise
来构造一个新的-只需链接到现有的{{1 }}根据需要与Promise
和.then
链接。这样的.catch
链可以有任意数量的个Promise
和.then
-仅仅是因为您消耗了.catch
和一个Promise
不会阻止您在其他地方使用相同的解析值。为了说明:
.then
换句话说-每次您想使用另一个makePromise()
.then((result) => {
console.log(result);
// Returning inside a `.then` will pass along the value to the next `.then`:
return result;
})
.then((result) => {
// this `result` will be the same as the one above
});
时都不需要构造一个new Promise
。所以:
然后我可能无法在findUserByEmail(“ test@example.com”)中然后.catch
是不正确的-您确实可以根据需要链接到具有多个.then
和.then
的现有Promise的末尾。
请注意,仅返回其参数并且不执行其他任何操作(例如.catch
)的.then
是多余的-它什么也不做。另外请注意,.then(currentUser => currentUser)
会捕获承诺拒绝并解析为已解决 .catch
。所以如果你这样做
Promise
function findUserByEmail(email) {
return User.findOne({email: email})
.then(currentUser => currentUser)
.catch(error => error)
}
意味着catch
的调用者将不能错误findUserByEmail
,因为在catch
中捕获了任何可能的错误” s findUserByEmail
。通常,最好允许错误渗入到函数的调用方中,例如,
catch
因此,除非您的someFunctionThatReturnsPromise('foobar')
.then((result) => {
// everything is normal, send the result
res.send(result);
})
.catch((err) => {
// there was an error, set response status code to 500:
res.status(500).send('there was an error');
})
或findUserByEmail
辅助函数需要在出现错误时进行特定的操作,否则最好返回{{1} }:
createNewUser
如果您的帮助器函数 do 在出现错误时需要执行某些操作,那么为确保错误正确传递给函数的调用者,我建议要么抛出错误Promise
内:
const findUserByEmail = email => User.findOne(email);
const createNewUser = newUserDetails => new User(newUserDetails).save();
,以便在其他人呼叫catch
时可以const findUserByEmail = email => User.findOne(email)
.catch((err) => {
// error handling - save error text somewhere, do a console.log, etc
throw err;
});
。否则,如果您执行类似的操作
catch
然后,findUserByEmail
的调用方必须检查const findUserByEmail = email => User.findOne(email)
.catch((err) => {
// do something with err
return err;
});
中的如果结果实际上是一个错误,这很奇怪:
findUserByEmail
更好地将错误抛出到.then
的{{1}}中,以便findUserByEmail('foo@bar.com')
.then((result) => {
if (result instanceof Error) {
// do something
} else {
// No errors
}
});
的使用者也可以 findUserByEmail
。
答案 1 :(得分:3)
在已有诺言的情况下用诺言构造函数创建诺言是没有意义的,这就是为什么将其称为诺言构造反模式的原因。
这是一个错误,reject("Error in findUserByEmail", error)
。 reject
仅接受1
论点,这是拒绝的原因。 error
将被忽略。约定错误是Error
对象而不是字符串。
该功能可以重构为:
const findUserByEmail = (emailAddress) => {
return User.findOne({email: emailAddress})
.then(response => response) // noop
.catch(error => {
const readableError = new Error('Error in findUserByEmail');
readableError.originalError = error;
throw readableError;
});
})
}
等
反模式不一定会导致性能下降,但会导致代码异味。它们使代码更难以阅读,维护和测试,也表明开发人员可能对该主题缺乏理解。
Promise构造函数对性能的影响很小。它引入了另一层嵌套,并导致了回调地狱-诺言应该有助于避免这种情况。
如果我在不添加新承诺的情况下更改了上述代码段<...> 那么我可能无法在findUserByEmail(“ test@example.com”)中进行.then和.catch吗?
不,一个诺言可以与then(...)
和catch(...)
(这是then(null, ...)
的语法糖)进行多次链接,这是该模式的优势。请注意,catch(err => { return err })
和catch(err => { throw err })
是不同的东西,前者捕获错误,后者抛出错误。