javascript - 了解显式承诺构造反模式
问题描述
在我之前的帖子中强调的CertainPerformance建议我参考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)
})
})
}
问题 1
现在,我假设CertainPerformance 说过度使用了promise,因为 return new Promise((resolve, reject) => {
当我已经在使用mongoose 的promise 时,我正在创建新的promise 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)
}
问题2
.then
那么我可能无法.catch
进入findUserByEmail("test@example.com")
?
在应用程序的 API 路由中,我将在其中调用该findUserByEmail("test@example.com")
函数,如果出现错误,我会想做其他事情(对于不同的情况会有所不同,因此我不能在我的辅助函数中使用它)。
问题 3
是否,现在做return new Promise((resolve, reject) => {
而不是只做一个 有意义,return User.findOne(
还是我错过了什么?
解决方案
因为.findOne
已经返回 a Promise
,所以不需要用new Promise
- 构造一个新的,只需根据需要用and链接到现有链上。这样的链可以有任意数量的s 和s - 仅仅因为你使用 a并不能阻止你在其他地方使用相同的 resolve 值。为了显示: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
每次你想要能够使用 another 时都不需要构造 a .then
。所以:
然后我可能无法在 findUserByEmail("test@example.com") 中使用 .then 和 .catch
.then
是不正确的 - 您确实可以使用任意数量的s 和.catch
es链接到现有 Promise 的末尾。
注意 a.then
只返回它的参数而不做任何其他事情(例如.then(currentUser => currentUser)
)是多余的——它根本不会做任何事情。另请注意, a.catch
将捕获Promise 拒绝并解析为已解决 Promise
。所以如果你这样做
function findUserByEmail(email) {
return User.findOne({email: email})
.then(currentUser => currentUser)
.catch(error => error)
}
这catch
意味着调用者 offindUserByEmail
将无法catch
出错,因为任何可能的错误都在' findUserByEmail
s中捕获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
或createNewUser
辅助函数需要在出现错误时执行特定操作,否则最好只返回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
是否实际上是一个错误,这很奇怪:
findUserByEmail('foo@bar.com')
.then((result) => {
if (result instanceof Error) {
// do something
} else {
// No errors
}
});
最好把错误扔进findUserByEmail
's catch
,这样消费者findUserByEmail
也可以 .catch
。
推荐阅读
- internet-explorer - 如何手动启用 HTML 文件的怪癖或几乎标准模式?
- codelite - Codelite 侧边栏不见了
- sql-server - 层级升级后无法访问 RDS SqlServer
- regex - 使用 REGEX 从 URL 中提取特定文本
- php - 限制购物车只能包含 1 个“品牌”
- react-native - 反应本机应用程序中的HTML文本,如何包含?
- javascript - 如何使用 Parcel Bundler 包含外部 JS 库,如 jQuery、jQuery DataTable、Charts.js?
- javascript - 我不知道如何在 sequelize (Mac) 中使用 POST 方法
- python - 在循环中创建多个绘图的 Python 方法?
- delphi - 升级到 Delphi 10.4 Sydney 时缺少 ToolsAPI 接口方法的实现