essayer / attraper des blocs avec async / wait

Je suis en train de creuser dans la fonction 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 retourner / lancer avec async / waiting, cependant, v8 n’optimise pas le code dans les blocs try / catch?

Y a-t-il des alternatives?

    Des alternatives

    Une alternative à cela:

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

    serait quelque chose comme ça, en utilisant des promesses explicitement:

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

    ou quelque chose comme ça, en utilisant le style de passage de continuation:

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

    Exemple original

    Ce que votre code original fait, c’est suspendre l’exécution et attendre que la promesse retournée par getQuote() se règle. Il poursuit ensuite l’exécution et écrit la valeur renvoyée dans var quote , puis l’affiche si la promesse a été résolue ou lance une exception et exécute le bloc catch qui imprime l’erreur si la promesse a été rejetée.

    Vous pouvez faire la même chose en utilisant l’API Promise directement comme dans le deuxième exemple.

    Performance

    Maintenant, pour la performance. Testons le!

    Je viens d’écrire ce code – f1() donne 1 comme valeur de retour, f2() lève 1 comme exception:

     function f1() { return 1; } function f2() { throw 1; } 

    Appelons maintenant le même code 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() en 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 eu pour f1 :

     $ time node throw-test.js 1000000 real 0m0.073s user 0m0.070s sys 0m0.004s 

    C'est ce que j'ai eu pour 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 de lancements par seconde en un seul processus. Si vous faites plus que cela, vous devrez peut-être vous en préoccuper.

    Résumé

    Je ne m'inquiéterais pas de choses comme ça dans Node. Si des choses comme celles-là sont utilisées, elles seront optimisées par les équipes V8 ou SpiderMonkey ou Chakra, et tout le monde les suivra.

    Même si ce n'est pas optimisé, je soutiendrais que si vous augmentez la puissance de votre CPU dans Node, vous devriez probablement écrire votre numéro en C - c'est ce que recherchent les addons natifs, entre autres choses. Ou peut-être que les choses comme node.native seraient mieux adaptées au travail que Node.js.

    Je me demande quel serait un cas d'utilisation nécessitant tant d'exceptions. Généralement, lancer une exception au lieu de renvoyer une valeur est une exception.

    Alternative similaire à la gestion des erreurs dans Golang

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

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

    Importez-la ensuite chaque fois que vous avez besoin de détecter des erreurs et enveloppez votre fonction asynchrone qui renvoie une promesse.

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

    Une alternative à try-catch block 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 que celle de try-catch.

     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 une variable possible pour contenir une erreur en haut, vous pouvez le faire.

     if (quote instanceOf Error) ... 

    Bien que cela ne fonctionne pas si quelque chose comme une erreur TypeError ou Reference est levé. Vous pouvez vous assurer qu’il s’agit d’une erreur régulière 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 cela est de tout encapsuler dans un gros bloc try-catch où de nombreuses promesses sont créées, ce qui complique la gestion de l’erreur en fonction de la promesse qui l’a créée. Avec l’alternative étant des blocs d’essais multiples que je trouve tout aussi encombrants

    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); }); 

    C’est similaire à l’erreur de manipulation avec co

     const test = opts => { return co(function*() { // do sth yield sthError(); return 'ok'; }).catch(err => { console.error(err); }); };