GOOGLE ADS

dimanche 1 mai 2022

Unexpected Promise.all() échoue comportement rapide - continue à s'exécuter après le rejet

Depuis MDN:

Promise.all est rejeté si l'un des éléments est rejeté. Par exemple, si vous transmettez quatre promesses qui se résolvent après un délai d'attente et une promesse qui est rejetée immédiatement, Promise.all sera immédiatement rejetée.

Discutons de l'extrait de code suivant :


(async () => {
try {
const awaited = await Promise.all([
(() => {
console.log('1');
return Promise.reject('2');
})(),
(() => {
console.log('3');
return Promise.resolve('4');
})(),
]);
console.log(awaited);
} catch (error) {
console.log(error);
} finally {
console.log('5');
}
})();

Solution du problème

Au lieu de cela, je vois un '3' également enregistré. Pourquoi en est-il ainsi?

Toutes les autres réponses tentent d'expliquer comment fonctionnent les promesses ou la boucle d'événements, mais en fait cela n'a rien à voir avec celles-ci.

L'argument que vous transmettez Promise.allest un tableau qui contient les résultats de deux appels de fonction. Par conséquent, les deux fonctions seront appelées avant Promise.alll'appel. Les deux fonctions console.logune valeur et renvoient ensuite une promesse.
Promise.allreçoit un tableau contenant ces promesses. Donc, avant de Promise.allfaire quoi que ce soit, les deux fonctions ont déjà été exécutées et enregistrées 1et 3respectivement.

Il est peut-être plus facile de vous voir restructurer votre code pour créer les promesses en amont :

(async () => {
try {
const promise1 = (() => {
console.log('1');
return Promise.reject('2');
})();
const promise2 = (() => {
console.log('3');
return Promise.resolve('4');
})()
const awaited = await Promise.all([promise1, promise2]);
console.log(awaited);
} catch (error) {
console.log(error);
} finally {
console.log('5');
}
})();

Comme pour toute autre fonction, tous les arguments de la fonction sont évalués avant que la fonction elle-même ne soit appelée. L'ordre des événements est plutôt celui-ci:

  • Le premier console.log est exécuté, enregistrant ainsi '1';

  • La promesse rejetée avec 2est créée.

  • Le second console.log est exécuté, enregistrant ainsi '3';

  • Promesse tenue avec 4est créé.

  • Un tableau contenant les deux promesses est créé.

  • Promise.all est appelé avec un tableau de promesses en paramètre.

  • Promise.all traite les promesses.

  • La clause 'catch' est exécutée, enregistrant la valeur rejetée de '2' ;

  • La clause 'Finalement' est exécutée quoi qu'il en soit, en enregistrant '5' ;

  • Voici un exemple plus simple : notez que rien n'est "fait" avec le deuxième argument passé à la fonction et pourtant la valeur est toujours enregistrée, précisément parce que tous les arguments sont évalués en premier :


    function process(arg) {
    return 'Received ' + arg;
    }
    const result = process(
    (() => {
    console.log('1');
    return 1;
    })(),
    (() => {
    console.log('3');
    return 2;
    })(),
    );
    console.log(result)

    Aucun commentaire:

    Enregistrer un commentaire

    Comment utiliseriez-vous .reduce() sur des arguments au lieu d'un tableau ou d'un objet spécifique ?

    Je veux définir une fonction.flatten qui aplatit plusieurs éléments en un seul tableau. Je sais que ce qui suit n'est pas possible, mais...