使用 bluebird 在顺序流中管理异步操作
Manage async operations in a sequential flow with bluebird
首先,我不会否认我对 promises 很陌生,并试图在我的新 Node.js 应用程序中更好地管理 promises。根据我从朋友和社区那里听到的消息,我正在使用 bluebird。这是一个场景:
该应用程序有一个注册流程,这是一个典型的用例,必须发生以下事件才能注册新用户:
- 检查用户是否已经存在。
- 如果没有,添加一个新用户。
- 发送验证邮件。
我确实有 3 个独立的函数来解决上述每个步骤。
下面是我使用 promises 流程得出的结果...但不知何故我不相信下面的代码:
user.isExistingUser(email)
.then((successData) => {
if(successData && successData.length === 0) {
user.signUp(signUpInfo)
.then((successData) => {
emailService.sendVerificationEmail(recipientInfo)
.then((successData) => {
res.json(responseUtility.getApiResponse(successData));
})
.catch((errorObj) => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
})
.catch((errorObj) => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
} else {
res.json(responseUtility.getApiResponse(null, [{
param: 'email',
msg: 'An account already exists with this email'
}], null));
}
})
.catch((errorObj) => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
如您所见,代码似乎有点太长,跟踪起来有点棘手。这里的一些蓝鸟专家可以帮助提供更好或更易读的代码吗?
您应该更好地利用链接。总是 return
从你的函数中承诺做一些异步的事情。
user.isExistingUser(email).then(successData => {
if (successData && successData.length === 0) {
return user.signUp(signUpInfo).then(() => {
// ^^^^^^
return emailService.sendVerificationEmail(recipientInfo);
// ^^^^^^
}).then(successData => {
res.json(responseUtility.getApiResponse(successData));
});
} else {
res.json(responseUtility.getApiResponse(null, [{
param: 'email',
msg: 'An account already exists with this email'
}], null));
}
}).catch(errorObj => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
我想实现相同代码的一种合理方式可能是这样;
user.isExistingUser(email)
.then(successData => successData &&
successData.length === 0 ? user.signUp(signUpInfo)
.then(successData => emailService.sendVerificationEmail(recipientInfo))
.then(successData => res.json(responseUtility.getApiResponse(successData)))
: res.json(responseUtility.getApiResponse(null, [{param: 'email', msg: 'An account already exists with this email'}], null)))
.catch(err => res.json(responseUtility.getApiResponse(null, null, err)));
不知道你的代码有什么问题
基本上,您的代码是嵌套回调。典型的嵌套回调是这样的:
funcation(args..,
function(args...,
function(args){...}
){...}
){...}
你的是这样的:
function(args).then(()=> {
function(args).then(() => {
function(args){...}
})
})
差别不大,不是吗?
这才是Promise的正确使用方式。
解决你的问题的关键是链接承诺。这其实就是承诺的全部意义。
基本上,您希望 then
回调到 return 一个承诺。这样你就可以链接你的承诺以避免代码的嵌套回调风格。
每个 .then
方法总是 return 本身就是一个承诺。
promiseB = promiseA.then(()=> {
// callback
return promiseC
});
如果callback
return 像上面这样的承诺,你可以有效地想到promiseB = promiseC
。现在,如果我们有
promiseC = promiseA.then(()=> {
// callback
return promiseB
});
promiseE = promiseC.then(()=> {
// callback
return promiseD
});
您可以将它们链接。那么上面可以缩短为:
promiseA.then(()=> {
// callback
return promiseB
}).then(()=> {
// callback
return promiseD
});
直接回答你的问题。
let userPromise = user.isExistingUser(email);
// handle new user
userPromise
.then((userData) => {
assert userData.length === 0;
// sign up
// Assuming user.signUp is a Promise with recipientInfo as its resolved value
return user.signUp(userData.signUpInfo);
})
.then((recipientInfo)=> {
// send verification email
// Assuming user.sentVerificationEmail is a Promise with emailSuccessData as its resolved value
return user.sentVerificationEmail(recipientInfo)
})
.then((emailSuccessData)=> {
res.json(responseUtility.getApiResponse(emailSuccessData));
})
// if any of the previous Promise is rejected,
// the follow .then will be effectively bypassed and fall though to this catch
.catch((err)=> {
res.json(responseUtility.getApiResponse(null, null, err));
})
// handle existing user
userPromise.then((successData) => {
assert successData.length > 0
const json = [{
param: 'email',
msg: 'An account already exists with this email'
}]
res.json(responseUtility.getApiResponse(null, json, null));
});
// no need to catch again. if userPromise is rejected, it will be handled by the catch above.
首先,我不会否认我对 promises 很陌生,并试图在我的新 Node.js 应用程序中更好地管理 promises。根据我从朋友和社区那里听到的消息,我正在使用 bluebird。这是一个场景:
该应用程序有一个注册流程,这是一个典型的用例,必须发生以下事件才能注册新用户:
- 检查用户是否已经存在。
- 如果没有,添加一个新用户。
- 发送验证邮件。
我确实有 3 个独立的函数来解决上述每个步骤。
下面是我使用 promises 流程得出的结果...但不知何故我不相信下面的代码:
user.isExistingUser(email)
.then((successData) => {
if(successData && successData.length === 0) {
user.signUp(signUpInfo)
.then((successData) => {
emailService.sendVerificationEmail(recipientInfo)
.then((successData) => {
res.json(responseUtility.getApiResponse(successData));
})
.catch((errorObj) => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
})
.catch((errorObj) => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
} else {
res.json(responseUtility.getApiResponse(null, [{
param: 'email',
msg: 'An account already exists with this email'
}], null));
}
})
.catch((errorObj) => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
如您所见,代码似乎有点太长,跟踪起来有点棘手。这里的一些蓝鸟专家可以帮助提供更好或更易读的代码吗?
您应该更好地利用链接。总是 return
从你的函数中承诺做一些异步的事情。
user.isExistingUser(email).then(successData => {
if (successData && successData.length === 0) {
return user.signUp(signUpInfo).then(() => {
// ^^^^^^
return emailService.sendVerificationEmail(recipientInfo);
// ^^^^^^
}).then(successData => {
res.json(responseUtility.getApiResponse(successData));
});
} else {
res.json(responseUtility.getApiResponse(null, [{
param: 'email',
msg: 'An account already exists with this email'
}], null));
}
}).catch(errorObj => {
res.json(responseUtility.getApiResponse(null, null, errorObj));
});
我想实现相同代码的一种合理方式可能是这样;
user.isExistingUser(email)
.then(successData => successData &&
successData.length === 0 ? user.signUp(signUpInfo)
.then(successData => emailService.sendVerificationEmail(recipientInfo))
.then(successData => res.json(responseUtility.getApiResponse(successData)))
: res.json(responseUtility.getApiResponse(null, [{param: 'email', msg: 'An account already exists with this email'}], null)))
.catch(err => res.json(responseUtility.getApiResponse(null, null, err)));
不知道你的代码有什么问题
基本上,您的代码是嵌套回调。典型的嵌套回调是这样的:
funcation(args..,
function(args...,
function(args){...}
){...}
){...}
你的是这样的:
function(args).then(()=> {
function(args).then(() => {
function(args){...}
})
})
差别不大,不是吗?
这才是Promise的正确使用方式。
解决你的问题的关键是链接承诺。这其实就是承诺的全部意义。
基本上,您希望 then
回调到 return 一个承诺。这样你就可以链接你的承诺以避免代码的嵌套回调风格。
每个 .then
方法总是 return 本身就是一个承诺。
promiseB = promiseA.then(()=> {
// callback
return promiseC
});
如果callback
return 像上面这样的承诺,你可以有效地想到promiseB = promiseC
。现在,如果我们有
promiseC = promiseA.then(()=> {
// callback
return promiseB
});
promiseE = promiseC.then(()=> {
// callback
return promiseD
});
您可以将它们链接。那么上面可以缩短为:
promiseA.then(()=> {
// callback
return promiseB
}).then(()=> {
// callback
return promiseD
});
直接回答你的问题。
let userPromise = user.isExistingUser(email);
// handle new user
userPromise
.then((userData) => {
assert userData.length === 0;
// sign up
// Assuming user.signUp is a Promise with recipientInfo as its resolved value
return user.signUp(userData.signUpInfo);
})
.then((recipientInfo)=> {
// send verification email
// Assuming user.sentVerificationEmail is a Promise with emailSuccessData as its resolved value
return user.sentVerificationEmail(recipientInfo)
})
.then((emailSuccessData)=> {
res.json(responseUtility.getApiResponse(emailSuccessData));
})
// if any of the previous Promise is rejected,
// the follow .then will be effectively bypassed and fall though to this catch
.catch((err)=> {
res.json(responseUtility.getApiResponse(null, null, err));
})
// handle existing user
userPromise.then((successData) => {
assert successData.length > 0
const json = [{
param: 'email',
msg: 'An account already exists with this email'
}]
res.json(responseUtility.getApiResponse(null, json, null));
});
// no need to catch again. if userPromise is rejected, it will be handled by the catch above.