我是node.js环境中的新手。我阅读了许多关于实现Promise并将它们链接在一起的来源。我试图避免反模式实现,但我无法弄明白我该怎么做。
系统中有用户注册流程。 首先,我检查用户名。 如果数据库中没有此用户名的用户,我创建一个用户模型并将其保存到数据库中。
你能否看到我的评论内联?
app.js
RegisterUser("existUser","123").then(user=>{
//send response, etc
}).catch(er => {
console.log(er);
//log error,send proper response, etc
// Should I catch error here or inner scope where RegisterUser implemented ?
});
userService.js
function RegisterUser(username, password) {
return new Promise((resolve, reject) => {
GetUser(username)
.then(user=>{
if(user)reject(new Error("User Exists"));
else{
resolve(SaveUser(username,password))// Is that ugly?
//what if I have one more repository logic here ?
//callback train...
}
})
.then(user => {
resolve(user);//If I do not want to resolve anything what is the best practice for it, like void functions?
}).catch(err=>{
console.log(err); // I catch the db error what will I do now :)
reject(err);// It seems not good way to handle it, isn't it ?
// Upper promise will handle that too. But I dont know how can I deal with that.
});;
});
}
repository.js
function GetUser(username) {
return new Promise((resolve, reject) => {
if (username === "existUser")
resolve("existUser");
else resolve("");
});
}
function SaveUser(username, password) {
return new Promise((resolve, reject) => {
reject(new Error("There is a problem with db"));//assume we forgot to run mongod
});
}
上面的代码对我来说似乎很糟糕。 我想我需要定义一些可以在GetUser方法之后链接的方法。 像
GetUser(username)
.then(SaveUserRefined)// how could it know other parameters like password, etc
.then(user=> {resolve(user)}) // resolve inside then ? confusing.
.catch(er=>//...);
我觉得我在这里做反模式并且创造了#34;承诺地狱" 如何实现这样的简单流程。 验证用户名并保存。
感谢。
答案 0 :(得分:4)
是的,那是Promise
constructor antipattern!只需写下
function registerUser(username, password) {
return getUser(username).then(user => {
if (user) throw new Error("User Exists");
else return saveUser(username,password)
});
}
注意我还小写了你的函数名。您应该只将构造函数大写。
我应该在这里发现错误还是在
registerUser
实施的内部范围?
您应该在可以处理它们的地方捕获错误 - 并且您应该在链的末尾处理错误(通常通过记录它们)。如果registerUser
没有提供回退结果,则不需要处理任何内容,并且通常也不需要自己记录错误消息(如果您愿意,请参阅{{3}例如)。
另见here。
答案 1 :(得分:3)
如果你已经在使用promises,那么就没有必要创建自己的promises。当你在一个promise上调用.then
并提供一个函数来说明该做什么时,会创建一个新的promise,它将解析为函数返回的任何内容。
所以你的registerUser函数应该是这样的:
function registerUser(username, password) {
return getUser(username)
.then(user => {
if (user) {
throw new Error('User Exists');
}
return saveUser(username, password)
});
}
你可以这样使用它:
registerUser('starfox', 'doABarrelRoll')
.catch(error => console.log(error);
请注意,如果SaveUser导致错误,它将在最终的.catch中结束,因为我没有在registerUser中放置任何错误处理。由您决定要处理错误的位置。如果它是可恢复的东西,也许registerUser可以处理它,外面的世界永远不需要知道。但是,如果用户名存在,您已经抛出错误,因此调用者无论如何都需要知道错误。
此外,你的getUser和saveUser函数也可以避免创建自己的promises,假设真正的实现调用了一些返回promise的函数。
答案 2 :(得分:0)
您应该使用async/await
语法以避免Promise Hell。
像这样更改代码
/**
* This is a promise that resolve a user or reject if GetUser or SaveUser reject
*/
async function RegisterUser (username, password) {
var user = await GetUser(username)
if (user)
return user;
var userSaved = await SaveUser(username,password)
return userSaved
}
如果您在RegisterUser
内使用async function
,只需进行编码
async function foo () {
try {
var usr = await RegisterUser('carlos', 'secret123')
return usr
} catch (e) {
console.error('some error', e)
return null
}
}
或者如果您像诺言般使用它
RegisterUser('carlos', 'secret123')
.then(usr => console.log('goood', usr))
.catch(e => console.error('some error', e))