如何根据 Promise 链中的阶段区分错误的来源
how to differentiate error's source based on stage in Promise chain
我有 2 个回调,它们都调用 API 和 return Promise
。他们应该按顺序去。让我们将它们命名为 verifyThing
和 updateThing
.
所以如果没有错误处理,它会像
一样简单
verifyThing()
.then((id) => updateThing(id))
但是现在错误处理来了。假设我需要在 verifyThing
失败或 updateThing
时显示不同的错误消息。同样显然,如果 verifyThing
失败,我不需要调用 updateThing
。
到目前为止我已经尝试过自定义错误:
class VerifyError extends Error {};
verifyThing()
.catch(e => {
message("cannot verify");
throw new VerifyError();
})
.then((id) => updateThing(id))
.catch(e => {
if (e instanceof VerifyError) return;
message("cannot update");
})
不幸的是我们使用 Babel 6.26 的自定义错误 check does not work。作为一个脏补丁,我可以抛出魔法字符串而不是错误子类,但 ESLint 规则是有原因的,对吧?
所以我终于得到了工作变体。但我认为它的可读性较差(因为嵌套):
verifyThing()
.catch(e => {
message("cannot verify");
throw e;
})
.then((id) =>
updateThing(id)
.catch(e => {
message("cannot update");
})
)
是否有任何其他方式来处理同一链中的所有逻辑?
看起来你想要的实际行为可以通过重新排序你的最后一个例子来实现:
verifyThing().then(id =>
updateThing(id).catch(e => {
message("cannot update");
})
).catch(e => {
message("cannot verify");
})
外部 catch()
只会捕获来自 verifyThing()
的错误,因为来自 updateThing(id)
的错误已由内部 catch()
处理。此外,您总是得到已解决的承诺而不是被拒绝的承诺,这是适当的,因为两种类型的错误都已得到处理。
为避免出现错误处理不贴近源头的情况,将内部部分移至辅助函数:
function tryUpdateThing (id) {
return updateThing(id).catch(e => {
message("cannot update");
});
}
verifyThing().then(
tryUpdateThing
).catch(e => {
message("cannot verify");
});
这是否是可以接受的可读性,我会留给你决定。
如果 async/await
是一个选项,那么:
async function() {
let id;
try {
id = await verifyThing();
await updateThing(id);
} catch(e) {
message(id === undefined ? "cannot verify" : "cannot update");
throw e;
}
}
这假设当 verifyThing()
满足时,它将以定义的值解析。
我有 2 个回调,它们都调用 API 和 return Promise
。他们应该按顺序去。让我们将它们命名为 verifyThing
和 updateThing
.
所以如果没有错误处理,它会像
一样简单verifyThing()
.then((id) => updateThing(id))
但是现在错误处理来了。假设我需要在 verifyThing
失败或 updateThing
时显示不同的错误消息。同样显然,如果 verifyThing
失败,我不需要调用 updateThing
。
到目前为止我已经尝试过自定义错误:
class VerifyError extends Error {};
verifyThing()
.catch(e => {
message("cannot verify");
throw new VerifyError();
})
.then((id) => updateThing(id))
.catch(e => {
if (e instanceof VerifyError) return;
message("cannot update");
})
不幸的是我们使用 Babel 6.26 的自定义错误 check does not work。作为一个脏补丁,我可以抛出魔法字符串而不是错误子类,但 ESLint 规则是有原因的,对吧?
所以我终于得到了工作变体。但我认为它的可读性较差(因为嵌套):
verifyThing()
.catch(e => {
message("cannot verify");
throw e;
})
.then((id) =>
updateThing(id)
.catch(e => {
message("cannot update");
})
)
是否有任何其他方式来处理同一链中的所有逻辑?
看起来你想要的实际行为可以通过重新排序你的最后一个例子来实现:
verifyThing().then(id =>
updateThing(id).catch(e => {
message("cannot update");
})
).catch(e => {
message("cannot verify");
})
外部 catch()
只会捕获来自 verifyThing()
的错误,因为来自 updateThing(id)
的错误已由内部 catch()
处理。此外,您总是得到已解决的承诺而不是被拒绝的承诺,这是适当的,因为两种类型的错误都已得到处理。
为避免出现错误处理不贴近源头的情况,将内部部分移至辅助函数:
function tryUpdateThing (id) {
return updateThing(id).catch(e => {
message("cannot update");
});
}
verifyThing().then(
tryUpdateThing
).catch(e => {
message("cannot verify");
});
这是否是可以接受的可读性,我会留给你决定。
如果 async/await
是一个选项,那么:
async function() {
let id;
try {
id = await verifyThing();
await updateThing(id);
} catch(e) {
message(id === undefined ? "cannot verify" : "cannot update");
throw e;
}
}
这假设当 verifyThing()
满足时,它将以定义的值解析。