Dois-je m'abstenir de gérer le rejet de la promesse de façon asynchrone?

je viens d'installer Node v7.2.0 et a appris que le code suivant:

var prm = Promise.reject(new Error('fail'));

résultats dans ce message:;

(node:4786) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: fail
(node:4786) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

je comprends le raisonnement derrière ceci comme beaucoup de programmeurs ont probablement éprouvé la frustration d'un Error finissant par être avalé par un Promise . Cependant j'ai fait cette expérience:

var prm = Promise.reject(new Error('fail'));

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
},
0)

qui résulte en:

(node:4860) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: fail
(node:4860) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:4860) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
fail

I sur la base du PromiseRejectionHandledWarning supposer que la manipulation d'un Promise rejet asynchrone est/pourrait être une mauvaise chose.

mais pourquoi?

13
demandé sur rabbitco 2016-12-01 23:53:45

2 réponses

"dois-je m'abstenir de manipuler de la Promesse de rejet de manière asynchrone?"

ces avertissements servent un but important mais pour voir comment tout cela fonctionne voir ces exemples:

essayez ceci:

process.on('unhandledRejection', () => {});
process.on('rejectionHandled', () => {});

var prm = Promise.reject(new Error('fail'));

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
}, 0);

ou ceci:

var prm = Promise.reject(new Error('fail'));
prm.catch(() => {});

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
}, 0);

ou ceci:

var var caught = require('caught');
var prm = caught(Promise.reject(new Error('fail')));

setTimeout(() => {
    prm.catch((err) => {
        console.log(err.message);
    })
}, 0);

Disclaimer: je suis l'auteur du module caught (et oui, je l'ai écrit pour cette réponse).

"1519300920 la" Justification

il a été ajouté au noeud comme l'un des changements de rupture entre v6 et v7 . Il y a eu une discussion houleuse à ce sujet dans numéro 830: comportement de détection de rejet non manipulé par défaut sans accord universel sur la façon dont les promesses avec les gestionnaires de rejet attachés de façon asynchrone devraient se comporter-travailler sans avertissements, travailler avec des avertissements ou être interdit d'utiliser du tout en mettant fin au programme. D'autres discussions ont eu lieu dans plusieurs numéros du projet unhandled-rejets-spec .

cet avertissement est pour vous aider à trouver des situations où vous avez oublié de gérer le rejet, mais parfois vous pouvez vouloir l'éviter. Par exemple, vous pouvez faire un tas de demandes et de stocker le promet dans un tableau, uniquement pour gérer plus tard dans une autre partie de votre programme.

l'Un des avantages de promesses, les rappels, c'est que vous pouvez séparer l'endroit où vous créez la promesse de l'endroit ou aux endroits où vous fixez les gestionnaires. Ces avertissements le rendent plus difficile à faire mais vous pouvez soit Gérer les événements (mon premier exemple) ou attacher un gestionnaire de capture fictif partout où vous créez une promesse que vous ne voulez pas gérer tout de suite (deuxième exemple). Ou vous pouvez demander à un module de le faire pour vous (troisième exemple).

éviter les Avertissements

attacher un handler vide ne change en rien la façon dont la promesse stockée fonctionne si vous le faites en deux étapes:

var prm1 = Promise.reject(new Error('fail'));
prm1.catch(() => {});

ce ne sera pas la même chose, cependant:

var prm2 = Promise.reject(new Error('fail')).catch(() => {});

ici prm2 sera une autre promesse que prm1 . Alors que prm1 sera rejeté "erreur" erreur prm2 sera résolu avec undefined qui n'est probablement pas ce que vous voulez.

mais vous pourriez écrire une fonction simple pour la faire fonctionner comme un exemple en deux étapes ci-dessus, comme je l'ai fait avec le caught module:

var prm3 = caught(Promise.reject(new Error('fail')));

ici prm3 est la même que prm1 .

voir: https://www.npmjs.com/package/caught

mise à jour 2017

Voir également Tirer la Demande n ° 6375: lib,src: "jeter" sur refus de promesse (pas encore fusionné en février 2017) qui est marqué comme Jalon 8.0.0 :

Fait des Promesses "jeter" les rejets qui sortie à l'instar des erreurs non interceptées . [soulignement ajouté]

cela signifie que nous pouvons nous attendre au noeud 8.x pour changer l'avertissement que cette question Est sur le point de devenir une erreur qui écrase et termine le processus et nous devrions en tenir compte lors de l'écriture de nos programmes aujourd'hui pour éviter des surprises dans le futur.

Voir Aussi Le noeud .js 8.0.0 Suivi de la Question n ° 10117 .

19
répondu rsp 2017-02-12 22:16:50

je suppose que la gestion asynchrone du rejet d'une promesse est une mauvaise chose.

Oui, en effet il est.

on s'attend à ce que vous voulez pour traiter les rejets immédiatement de toute façon. Si vous omettez de le faire (et éventuellement échouer à jamais manipuler), vous recevrez un avertissement.

Je n'ai connu pratiquement aucune situation où vous ne voudriez pas échouer immédiatement après avoir obtenu un rejet. Et même si vous devez attendre quelque chose de plus après l'échec, vous devriez le faire explicitement.

je n'ai jamais vu un cas où il serait impossible d'installer immédiatement le gestionnaire d'erreur (essayer de me convaincre du contraire). Dans votre cas, si vous voulez un message d'erreur légèrement retardé, il suffit de faire

var prm = Promise.reject(new Error('fail'));

prm.catch((err) => {
    setTimeout(() => {
        console.log(err.message);
    }, 0);
});
1
répondu Bergi 2016-12-01 23:51:03