我开始越来越多地实施承诺,并且不确定它们应该如何实施。
例如,考虑一个注册函数,它接受电子邮件地址,用户名和密码,并按顺序执行以下异步操作:
如果在任何步骤中出现问题,则暂停进度并将JSON对象发送回用户以通知他们该问题。否则,将通知用户他们已成功注册。
如何使用promises实现此功能/错误处理?
以电子邮件检查(返回承诺)为例。如果查询数据库时发生错误,则显然应该拒绝承诺。如何处理实际的电子邮件检查?
例如,如果电子邮件地址已经注册,并且checkEmail函数中指定了错误对象,是否应该拒绝承诺?
e.g。
function checkEmail(email) {
return new Promise((resolve, reject) => {
// check email against database
// if database error occurs, reject()
if (email already registered) {
reject({error: 'email already registered'});
} else {
resolve(); // move on to check username
}
});
}
使用此样式会产生如下所示的承诺链:
checkEmail(email)
.then(() => checkUsername(username))
.then(() => hashPassword(password))
.then(passwordHash => addUser(email, username, passwordHash))
.then(() => {
// notify user of successful signup
})
.catch(error => {
// all error objects are passed here
// can then simply send error object directly to client
/* if different error handling functionality is needed,
additional property can be included on error object passed to
resolve(), and used to differentiate between errors */
});
或者应该在checkEmail函数中解析promise还是将处理checkEmail()结果的函数延迟到链中的下一个函数?
e.g。
function checkEmail(email) {
return new Promise((resolve, reject) => {
// check email against database
// if database error occurs, reject()
resolve(result); // process result / potential errors in next step of chain
});
}
然后会产生类似于以下内容的内容:
checkEmail(email)
.then((result) => {
if (email already registered) {
// error handling specified here, instead of in checkEmail()
return Promise.reject({error: 'email already registered'});
}
})
.then()...
.then()...
.then()...
.catch(error => {/* handle errors */});
这会导致更长/更混乱的承诺链,但似乎更灵活。
无论如何,我不确定如何说出来,所以希望这些例子说明我想要达到的目的。我刚刚开始实施承诺,而且对此很多都不确定。这有什么问题吗?这些方法中的一种优于另一种吗?有没有更好的方法来实现这些承诺链/处理错误?
非常感谢任何帮助/建议。
由于
答案 0 :(得分:1)
这完全取决于你做出拒绝的内容以及你的回报价值。承诺的方式是用链接设计的,你通常希望拒绝意味着你希望链条中止的东西。如果一个条件可能希望链继续而没有特殊处理,那么它不应该拒绝,因为很明显,拒绝将中止promise链而不在.catch()
处理程序中进行特殊处理以保持链的运行。
fetch()
示例是一个有趣的案例,我认为,它解释了一个常见问题,即您不仅仅有结果或错误的二进制结果。在fetch()
的示例中,您有一个明确的错误,您无法联系服务器,这确实是拒绝。并且,您可以在成功联系服务器并获得结果的情况下获得明确的结果。然后,你有一个中间案例,你成功地联系了服务器并获得了除2xx以外的某种状态(甚至可能是404)。在fetch()
的情况下,他们决定拒绝将被定义,因为它们无法到达服务器,所有其他返回值将被视为成功呼叫并将解决。
虽然我认为fetch()
的设计决策对于通用设计具有逻辑意义,但是有很多很多情况下实际上并不是你想要的东西。我经常使用一个小的包装器来检查状态仅在状态为2xx时解析。如果您正在尝试获取特定页面,那么在这种情况下成功只有在您获得页面时才会成功 - 其他一切只是一种不同类型的失败。因此,理想的设计确实在呼叫者的眼中。通常没有完美的解决方案。
所以,这是我的一般准则:
.catch()
处理程序进行干预来决定链是否应该继续。.then()
处理程序中如何继续。null
或类似的东西。期望值的链条应该可能拒绝。而且,如果他们想要一种更不寻常的行为,呼叫者总是可以使用.catch()
进行自定义。fetch()
甚至无法联系服务器),那么在所有情况下这显然都是拒绝。在您的具体情况中,您说明了这一点:
如果在任何步骤中出现问题,则暂停进度并将JSON对象发送回用户以通知他们该问题。否则,将通知用户他们已成功注册。
这似乎非常简单,只要你想要暂停进度,你就应该拒绝使用描述性错误对象。然后你可以运行链,如果它拒绝,你有一个错误对象反馈给用户。如果连锁店没有拒绝,那你就取得了成功。
以电子邮件检查(返回承诺)为例。如果查询数据库时发生错误,则显然应该拒绝承诺。如何处理实际的电子邮件检查?
例如,如果电子邮件地址已经注册,并且checkEmail函数中指定了错误对象,是否应该拒绝承诺?
根据我们之前的讨论,如果已经注册的电子邮件是您要中止链并将错误对象反馈给用户,那么您可能想要拒绝它已经注册。如果这是一个良性的操作,他们的电子邮件已经注册,并且操作链可以继续正常,那么你就可以解决它已经存在的问题。我没有完全遵循你的逻辑,但如果用户要求注册一个新帐户,那么已经存在的电子邮件地址可能是一个错误,因此被拒绝,因为这是一个帐户冲突,你不能拥有另一个帐户相同的识别电子邮件。