提问人:AndreA 提问时间:9/6/2023 最后编辑:KeithAndreA 更新时间:9/6/2023 访问量:53
嵌套异步函数调用中的错误管理 [duplicate]
Error management in nested async function calls [duplicate]
问:
我正在使用 Office JS API 开发一个 Excel 加载项。我有一个任务窗格,它正在运行类似于以下内容的代码:
var failA = true
var failB = true
// In reality this is Excel.run, and it injects a context
async function run(f) {
f()
}
// Simulate a failing async call
async function fail(message, delay) {
setTimeout(()=>{
throw new Error(message)
}, delay)
}
// Simulate a successful async call
async function success(message, delay) {
setTimeout(delay)
}
async function doA() {
console.log("Inside A");
if (failA) {
console.log("Failing A");
await fail("Error A", 1000)
} else {
success("Success A")
}
console.log("Done A")
}
async function doB() {
console.log("Inside B");
if (failB) {
console.log("Failing B");
await fail("Error B", 1000)
} else {
success("Success B")
}
console.log("Done B")
}
async function main () {
try {
// This is how Excel.run is called in all the Office samples
await run(async ()=>{
console.log("Start main");
await doA();
console.log("Between A and B");
await doB();
console.log("Finished");
})}
catch (error) {
console.log("ERROR: " + error.message)
}
}
// Need to await main in an async context. In reality main is run from a button
(async () => await main())()
.as-console-wrapper { min-height: 100%!important; top: 0; }
我希望错误冒泡并中断 .然后,输出应为:doA
doB
Start main
Inside A
Failing A
ERROR: Error A
相反,我得到的是:
Start main
Inside A
Failing A
Done A
Between A and B
Inside B
Failing B
Done B
Finished
后跟两个未捕获的异常和 。Error A
Error B
我做错了什么?我可以在不换行的情况下实现我所期望的行为并单独分装在块中吗?doA
doB
try...catch
答:
1赞
Keith
9/6/2023
#1
setTimeout
对承诺一无所知。相反,使用基于承诺的睡眠来等待。
此外,您忘记了在您的函数中,或者至少将其返回以保持承诺链完好无损。await f()
run
var failA = true
var failB = true
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
// In reality this is Excel.run, and it injects a context
async function run(f) {
await f()
}
// Simulate a failing async call
async function fail(message, delay) {
await sleep(delay);
throw new Error(message)
}
// Simulate a successful async call
async function success(message, delay) {
await sleep(delay);
}
async function doA() {
console.log("Inside A");
if (failA) {
console.log("Failing A");
await fail("Error A", 1000)
} else {
success("Success A")
}
console.log("Done A")
}
async function doB() {
console.log("Inside B");
if (failB) {
console.log("Failing B");
await fail("Error B", 1000)
} else {
success("Success B")
}
console.log("Done B")
}
async function main() {
try {
// This is how Excel.run is called in all the Office samples
await run(async () => {
console.log("Start main");
await doA();
console.log("Between A and B");
await doB();
console.log("Finished");
})
}
catch (error) {
console.log("ERROR: " + error.message)
}
}
// Need to await main in an async context. In reality main is run from a button
(async () => await main())()
.as-console-wrapper { min-height: 100%!important; top: 0; }
1赞
trincot
9/6/2023
#2
存在以下几个问题:
fail
未模拟失败的异步调用。它返回一个立即兑现的承诺。稍后将引发错误的回调与该 promise 无关,因为该回调是从新的调用堆栈执行的。同样,启动一个与它返回的承诺无关的,它再次立即得到实现。setTimeout
success
setTimeout
run
没有将其解决方案与 返回的 promise 的命运联系起来,因此返回一个 Promise 在未监控错误的情况下实现。如果拒绝,则不会捕获它。f
run
f
f
run
如果将脚本配置为执行,则需要执行它,否则其延迟将不起作用。
success
await
这是一个修复程序:
var failA = true;
var failB = true;
async function run(f) {
// Link to the returned promise, so error handling around
// run() will deal with rejections
return f();
}
// Helper function
const expire = ms => new Promise(resolve => setTimeout(resolve, ms));
async function fail(message, delay) {
await expire(delay);
// throw must happen in the execution context of function fail
throw new Error(message);
}
async function success(message, delay) {
// Wait for the delay to expire, otherwise it is useless
await expire(delay);
}
async function doA() {
console.log("Inside A");
if (failA) {
console.log("Failing A");
await fail("Error A", 1000);
} else {
await success("Success A"); // Must await it
}
console.log("Done A");
}
async function doB() {
console.log("Inside B");
if (failB) {
console.log("Failing B");
await fail("Error B", 1000);
} else {
await success("Success B"); // Must await it
}
console.log("Done B");
}
async function main () {
try {
await run(async ()=>{
console.log("Start main");
await doA();
console.log("Between A and B");
await doB();
console.log("Finished");
})
} catch (error) {
console.log("ERROR: " + error.message);
}
}
main();
评论
fail()
success()
throw
setTimeout
async
throw