javascript - Korrekt placering av try/catch-block vid användning av icke-omedelbar async/await
Jag har använt async/await i 6 månader och älskat den syntaktiska sockret. Jag använder det vanligtvis på det traditionella sättet:
try {
await doSomethingAsync()
}
catch (e) {}
På senaste tiden har jag börjat experimentera med att inte awaita omedelbart så att jag kan köra lite extra kod i detta sammanhang innan jag väntar på de asynkrona uppgifterna, som:
let p = doSometiongAsync()
... do more stuff
await p;
eller :
let p1 = doJob1();
let p2 = doJob2();
... do more synchronous stuff ...
await p1;
await p2;
Frågan är, var den korrekta placeringen av try/catch-blocken är för att säkerställa att fel (antingen synkrona eller asynkrona) inom anropen fångas korrekt. Är det runt det initiala funktionsanropet:
try {
let p = doSomethingAsync()
} catch(errors) {}
... do stuff ...
await p
eller försök med block runt await... eller två olika try-block, ett för varje?
try {
let p = doSomethingAsync()
} catch(errors) {}
... do stuff
try {
await p;
} catch (evenmoreerrors) {}
tack!
Svar #1
Det beror på vad doSomethingAsync är: en async-funktion, eller en icke-async-funktion som returnerar ett löfte.
Om det är en async-funktion
...du behöver bara try/catch runt await; en async-funktion kastar aldrig synkront (även om undantaget kastas av den initiala synkrona delen av den).
Exempel :
async function foo() {
// Note this is in the synchronous portion
console.log("synchronous part of foo");
if (true) {
throw new Error();
}
return new Promise(resolve => {
resolve();
});
}
(async () => {
const p = foo(); // No uncaught error
try {
await p;
} catch (e) {
console.log("Caught the error");
}
})().catch(e => {
console.log("Failed to catch it!");
});Om det är en icke-async-funktion som returnerar ett löfte
...beroende på funktionen kan du behöva try/catch på båda ställena, eller inte, beroende på hur det är skrivet. Om det kan kasta i sin synkrona kod, behöver du try/catch runt det. Och du behöver try/catch runt await vid eventuell promise-avslag.
Exempel på att inte hantera den synkrona delen:
function foo() {
// Note this is in the synchronous portion
console.log("synchronous part of foo");
if (true) {
throw new Error();
}
return new Promise(resolve => {
resolve();
});
}
(async () => {
const p = foo(); // No uncaught error
try {
await p;
} catch (e) {
console.log("Caught the error");
}
})().catch(e => {
console.log("Failed to catch it!");
});Exempel på att misslyckas med att fånga löftesavslaget:
function foo() {
// Note this is in the synchronous portion
console.log("synchronous part of foo");
return new Promise((resolve, reject) => {
reject();
});
}
(async () => {
try {
const p = foo();
} catch (e) {
console.log("Caught the error");
}
await p;
})().catch(e => {
console.log("Failed to catch it!");
});Svar #2
I båda fallen kan fel uppstå, ett i resultatet av det asynkrona anropet, och ett kan också uppstå om du har någon logik innan return-satsen i det asynkrona anropet, när din funktion inte är async. Det beror på din logik var du ska placera try/catch.
Om du vet att ett fel bara kan finnas vid det asynkrona anropet, sätt try/catch endast vid await-uttrycket.
