web-dev-qa-db-fra.com

Corriger les erreurs dans les promesses JavaScript avec un premier niveau

Donc, je veux que mon attrape de premier niveau soit celui qui gère l'erreur. Y a-t-il un moyen de propager mon erreur jusqu'à cette première prise?

Code de référence ne fonctionne pas (encore):

Promise = require('./framework/libraries/bluebird.js');

function promise() {
    var promise = new Promise(function(resolve, reject) {
        throw('Oh no!');
    });

    promise.catch(function(error) {
        throw(error);
    });
}

try {   
    promise();
}
// I WANT THIS CATCH TO CATCH THE ERROR THROWN IN THE PROMISE
catch(error) {
    console.log('Caught!', error);
}
25
Kirk Ouimet

Avec la nouvelle syntaxe async/wait - vous pouvez y parvenir. Veuillez noter qu'au moment de la rédaction, tous les navigateurs ne le supportent pas, vous devez probablement transpiler votre code avec babel (ou quelque chose de similaire).

// Because of the "async" keyword here, calling getSomeValue()
// will return a promise.
async function getSomeValue() {
  if (somethingIsNotOk) {
    throw new Error('uh oh');
  } else {
    return 'Yay!';
  }
}

async function() {
  try {
    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);
  } catch (error) {
    console.error(error);
  }
}
15
Edo

Vous ne pouvez pas utiliser d'instructions try-catch pour gérer les exceptions levées de manière asynchrone, car la fonction a "renvoyé" avant qu'aucune exception ne soit levée. Vous devriez plutôt utiliser les méthodes promise.then et promise.catch, qui représentent l'équivalent asynchrone de l'instruction try-catch.

Ce que vous devez faire est de renvoyer la promesse, puis enchaînez-y un autre .catch:

function promise() {
    var promise = new Promise(function(resolve, reject) {
        throw('Oh no!');
    });

    return promise.catch(function(error) {
        throw(error);
    });
}

promise().catch(function(error) {
    console.log('Caught!', error);
});

Les promesses sont chaînables, donc si une promesse relance une erreur, elle sera déléguée au prochain .catch.

En passant, vous n'avez pas besoin de parenthèses autour des instructions throw (throw a est identique à throw(a)).


Si vous exécutez ce code dans Node.js et que, pour une raison quelconque, vous n'êtes pas autorisé à modifier la fonction promise, vous pouvez utiliser des domaines pour le faire. Notez que les domaines ne sont pas vraiment les plus faciles à gérer et ont des cas Edge gênants dans certaines circonstances. À moins que vous n'ayez vraiment à le faire, je vous recommande fortement d'utiliser des promesses à la place.

25
Qantas 94 Heavy

Non! C'est complètement impossible, car les promesses sont intrinsèquement asynchrones. L'exécution de la clause try-catch sera terminée lorsque l'exception sera levée (et le voyage dans le temps n'aura toujours pas été inventé).

Au lieu de cela, renvoyez les promesses de toutes vos fonctions et ajoutez-y un gestionnaire d'erreurs.

5
Bergi

Je trouve souvent qu'il est nécessaire de veiller à ce qu'une promesse soit retournée et presque aussi souvent que nécessaire de gérer une erreur locale et de la rediffuser éventuellement. 

function doSomeWork() {
  return Promise.try(function() {

    return request.get(url).then(function(response) {
      // ... do some specific work
    });

  }).catch(function(err) {
    console.log("Some specific work failed", err);
    throw err; // IMPORTANT! throw unless you intend to suppress the error
  });
}

L'avantage de cette technique (Promise.try/catch) est que vous démarrez/assurez une chaîne Promise sans l'exigence de résolution/rejet qui peut facilement être manquée et créez un cauchemar de débogage.

2
kingdango

Pour développer la réponse de edo , si vous voulez détecter les erreurs d’une fonction async que vous ne voulez pas attendre. Vous pouvez ajouter une déclaration d'attente à la fin de votre fonction.

(async function() {
  try {
    const asyncResult = someAsyncAction();

    // "await" will wait for the promise to resolve or reject
    // if it rejects, an error will be thrown, which you can
    // catch with a regular try/catch block
    const someValue = await getSomeValue();
    doSomethingWith(someValue);

    await asyncResult;
  } catch (error) {
    console.error(error);
  }
})();

Si someAsyncAction échoue, l'instruction catch le gérera.

0
Jonathan Felchlin