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.

Relaterade artiklar