211 votes

essayer / attraper des blocs avec async / wait

Je creuse dans la fonctionnalité asynchrone / wait du noeud 7 et continue de trébucher sur du code comme celui-ci

 async function main() {
  try {
    var quote = await getQuote();
    console.log(quote);
  } catch(error) {
    console.error(error);
  }
}
 

Cela semble être la seule possibilité de résoudre / rejeter ou de renvoyer / jeter avec async / wait, cependant, la v8 n'optimise pas le code dans les blocs try / catch?!

Y a-t-il des alternatives?

235voto

rsp Points 11526

Alternatives

Une alternative à cela:

async function main() {
  try {
    var quote = await getQuote();
    console.log(quote);
  } catch (error) {
    console.error(error);
  }
}

serait quelque chose comme cela, à l'aide de promesses explicitement:

function main() {
  getQuote().then((quote) => {
    console.log(quote);
  }).catch((error) => {
    console.error(error);
  });
}

ou quelque chose comme cela, à l'aide de continuation passing style:

function main() {
  getQuote((error, quote) => {
    if (error) {
      console.error(error);
    } else {
      console.log(quote);
    }
  });
}

Exemple d'origine

Ce que votre code d'origine n'est la suspension de l'exécution et d'attendre la promesse du retournés par getQuote() pour s'établir. Ensuite, il continue l'exécution et écrit la valeur retournée var quote , puis l'imprime si la promesse a été résolu, ou lève une exception et exécute le bloc catch qui imprime le message d'erreur si la promesse a été rejetée.

Vous pouvez faire la même chose à l'aide de la Promesse de l'API directement comme dans le deuxième exemple.

Performance

Maintenant, pour la performance. Nous allons tester!

J'ai juste écrit ce code - f1() donne 1 comme valeur de retour, f2() jette 1 comme une exception:

function f1() {
  return 1;
}

function f2() {
  throw 1;
}

Maintenant, nous allons appeler le même code de millions de fois, d'abord avec f1():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
  try {
    sum += f1();
  } catch (e) {
    sum += e;
  }
}
console.log(sum);

Et puis changeons f1() de f2():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
  try {
    sum += f2();
  } catch (e) {
    sum += e;
  }
}
console.log(sum);

C'est le résultat que j'ai pour l' f1:

$ time node throw-test.js 
1000000

real    0m0.073s
user    0m0.070s
sys     0m0.004s

C'est ce que j'ai pour l' f2:

$ time node throw-test.js 
1000000

real    0m0.632s
user    0m0.629s
sys     0m0.004s

Il semble que vous pouvez faire quelque chose comme 2 millions jette une deuxième dans un processus monothread. Si vous faites plus que cela, alors vous pouvez avoir besoin de s'inquiéter à ce sujet.

Résumé

Je ne voudrais pas vous soucier de choses comme ça dans le Nœud. Si des choses comme qui beaucoup elle sera optimisée par la suite par le V8 ou SpiderMonkey ou Chakra équipes et tout le monde va suivre - c'est pas comme si il n'est pas optimisé comme un principe, c'est tout simplement pas un problème.

Même si il n'est pas optimisé alors que j'avais encore affirmer que si vous êtes dépasser le maximum de votre CPU dans le Nœud, alors vous devriez probablement écrire votre numéro de croquant dans C - qu'est ce que le natif addons sont pour, entre autres choses. Ou peut-être des choses comme nœud.natif serait mieux adapté pour le travail qu'Node.js.

Je me demandais ce qui serait un cas d'utilisation qui doit balancer de nombreuses exceptions. Habituellement, la levée d'une exception au lieu de retourner une valeur est, ainsi, une exception.

36voto

Steve Banton Points 408

Alternative similaire à la gestion des erreurs à Golang

Comme async / wait utilise des promesses sous le capot, vous pouvez écrire une petite fonction utilitaire comme celle-ci:

 export function catchEm(promise) {
  return promise.then(data => [null, data])
    .catch(err => [err]);
}
 

Puis importez-le chaque fois que vous avez besoin de détecter certaines erreurs et enveloppez votre fonction asynchrone qui renvoie une promesse avec.

 import catchEm from 'utility';

async performAsyncWork() {
  const [err, data] = await catchEm(asyncFunction(arg1, arg2));
  if (err) {
    // handle errors
  } else {
    // use data
  }
}
 

28voto

Pulkit chadha Points 309

Une alternative au bloc try-catch est wait-to-js lib. Je l'utilise souvent. Par exemple:

 import to from 'await-to-js';

async function main(callback) {
    const [err,quote] = await to(getQuote());

    if(err || !quote) return callback(new Error('No Quote found');

    callback(null,quote);

}
 

Cette syntaxe est beaucoup plus propre comparée à try-catch.

21voto

Tony Points 168
async function main() {
  var getQuoteError
  var quote = await getQuote().catch(err => { getQuoteError = err }

  if (getQuoteError) return console.error(err)

  console.log(quote)
}

Sinon, au lieu de déclarer un possible var pour organiser une erreur en haut, vous pouvez faire

if (quote instanceof Error) {
  // ...
}

Bien que cela ne fonctionnera pas si quelque chose comme une erreur TypeError ou d'erreur de Référence est levée. Vous pouvez vous assurer que c'est une erreur, même si avec

async function main() {
  var quote = await getQuote().catch(err => {
    console.error(err)      

    return new Error('Error getting quote')
  })

  if (quote instanceOf Error) return quote // get out of here or do whatever

  console.log(quote)
}

Ma préférence pour le présent est enveloppant tout dans un gros bloc try-catch où il y a plusieurs promet d'être créé peut faire lourd à gérer l'erreur spécifiquement à la promesse qui l'a créé. Avec l'alternative de plusieurs blocs try-catch que je trouve tout aussi lourd

1voto

Cooper Hsiung Points 11

J'aimerais faire comme ça :)

 const sthError = () => Promise.reject('sth error');

const test = opts => {
  return (async () => {

    // do sth
    await sthError();
    return 'ok';

  })().catch(err => {
    console.error(err); // error will be catched there 
  });
};

test().then(ret => {
  console.log(ret);
});
 

Cela ressemble à une erreur de traitement avec co

 const test = opts => {
  return co(function*() {

    // do sth
    yield sthError();
    return 'ok';

  }).catch(err => {
    console.error(err);
  });
};
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X