3
votes

Briser une chaîne Promise à l'intérieur de la boucle for

Je travaille sur une chaîne de promesses inspirée de cette réponse: https://stackoverflow.com/a/44955506/7485805

Je veux interrompre cette boucle for afin de gérer correctement le rejet de la chaîne. Je viens de me dire que je ne peux pas utiliser break dans la méthode .catch de la chaîne.

Voici mon code si cela aide: p >

.then(() => {
  if(i === (length - 1) )
    resolve();
})

x, y, z sont trois fonctions enchaînées dans la fonction pro Tandis que x se résout avec succès, y est exécuté mais est rejeté.

Je veux arrêter l'exécution de z depuis il est inutile de continuer et peut produire une erreur dans le code réel.

De plus, si quelqu'un peut me recommander une meilleure version pour ce morceau de code:

function pro (arr) {
  let chain = Promise.resolve();
  const self = {req: {}, res: {}};
  const length = arr.length;

  return new Promise((resolve, reject) => {
    for(let i=0; i<length; i++){
      chain = chain
          .then(() => arr[i].call(self) )
          .then(() => {
            if(i === (length - 1) )
              resolve();
          })
          .catch(e => {
            reject(e);
          })
    }
  })
  .then(() => {
    return self
  })
  .catch(e => {
    throw new Error (e);
  })

}

const x = function () {
  const self = this;
  return new Promise(resolve => {
    self.req = {key: "value"}
    resolve();
  })  
}

const y =  function () {
  const self = this;
  return new Promise((resolve, reject) => {
    console.log(self);
    reject();
  })
}

const z = function () {
  const self = this;
  return new Promise((resolve, reject) => {
    console.log('failed');
  })
}



pro([x, y, z])
.then((self) => {
  console.log('final',self);
})
.catch(e => {
  console.log('error', e);
})

Remarque: je ne peux pas utiliser await car ce code sera exécuté côté serveur et l'utilisation de await peut bloquer d'autres requêtes entrantes.


5 commentaires

"Je veux interrompre cette boucle for" Voir cette réponse à Exécutez plusieurs promesses récursives et interrompez-les sur demande . Pourquoi la boucle doit-elle être interrompue pour gérer une erreur? Que signifie "break" dans le contexte?


@Bergi Veuillez consulter le lien: es6console.com/jsjdb5rx


" y est exécuté mais est rejeté, je veux arrêter l'exécution de z " - euh, si vous avez construit votre chaîne de la même manière que dans la réponse que vous avez liée, alors z n'est pas exécuté du tout?! Votre problème est que .catch (e => {refuse (e);}) qui ne gère pas réellement l'erreur


Évitez la Promise anti-modèle du constructeur !


Est-ce cela ce que vous essayez d'accomplir?


3 Réponses :


2
votes

C'est beaucoup plus facile à faire avec la syntaxe async / await :

async function pro(arr) {
    const self = {req: {}, res: {}};
    for(const f of arr) await f.call(self);
    return self;
}

const x = function () {
  const self = this;
  return new Promise(resolve => {
    self.req = {key: "value"}
    resolve();
  })  
}

const y =  function () {
  const self = this;
  return new Promise((resolve, reject) => {
    console.log(self);
    reject("y failed");
  })
}

const z = function () {
  const self = this;
  return new Promise((resolve, reject) => {
  	console.log('failed');
  })
}

pro([x, y, z]).then((self) => {
  console.log('final',self);
})
.catch(e => {
  console.log('error', e);
});

async function pro(arr) {
    const self = {req: {}, res: {}};
    for(const f of arr) await f.call(self);
    return self;
}


2 commentaires

Êtes-vous sûr que l'utilisation de await ne bloquera pas les autres requêtes entrantes sur le serveur de nœuds?


Non, wait ne bloque pas . Cela rend la fonction retour immédiatement avec une promesse. Son contexte est rétabli lorsque cette promesse se résout.



2
votes

Quelques petites choses: lorsque vous construisez votre chaîne de promesses à l'intérieur d'une boucle for, c'est tout ce qui se passe: la chaîne est construite. L'exécution de .then aura lieu au plus tôt dans la prochaine boucle d'événements. Je vais essayer d'illustrer:

var promiseChain = functionReturningPromise();
for(var i=0;i<3;i++){
  promiseChain = promiseChain.then(x=> {
    return anotherPromiseFunction(x);
  });
}

En fonction de ce que fait réellement functionReturningPromise , quelque chose s'est peut-être déjà produit à ce stade ... ou peut-être pas. Par exemple, nous avons peut-être commencé une fetch , ou peut-être lancé un WebWorker. Cependant, si nous avions un setTimeout imbriqué à l'intérieur de la première promesse, alors tout ce que nous avons fait a été de mettre le rappel setTimeout dans la file d'attente pour le prochain cycle de la boucle d'événements. Mais garanti à 100%, aucune fonction .then n'est encore exécutée. Cela vient plus tard, dans la prochaine boucle d'événements.

La prochaine boucle d'événements arrive et la promesse est résolue. Cela signifie que le prochain .then sera exécuté. Disons que cela échoue. À ce stade, parce que nous avons enchaîné les promesses ( promiseChain = promiseChain.then ), nous passons immédiatement au premier .catch (ou .then avec un deuxième paramètre) dans la chaîne, et tous les .then intervenant sont complètement ignorés sans être exécutés. Ou s'il n'y a pas de catch es, alors cette chaîne de promesse est terminée. Aucune pause nécessaire; c'est juste la façon dont les promesses fonctionnent.

Donc, si vous ajoutez simplement un .catch à la toute fin de la chaîne, vous êtes bon.

À propos de ça chose "boucle d'événement": Je recommande vraiment de regarder Jake Archibald: dans The Loop , de JSConf.Asia 2018.

Aussi à propos de await ... On dirait qu'il y a une certaine confusion sur son fonctionnement. Vous ne pouvez utiliser wait que dans une fonction async , vous ne pouvez donc jamais bloquer complètement l'exécution du thread avec un seul wait . Cela fonctionne comme le chaînage de .puis , juste du sucre syntaxique. Donc, @trincot a définitivement raison, vous serez beaucoup plus satisfait de cette syntaxe.


1 commentaires

J'aime vraiment l'explication ici. Merci beaucoup. De plus, vous venez de dissiper mes doutes sur wait et je vais certainement regarder le lien JSConf.



1
votes

Voici une réponse alternative qui exécute simplement les promesses les unes après les autres, sauf si une promesse a été rejetée qui est ensuite arrêtée. Cela n'utilise pas await mais cela devrait vous donner une idée générale de la façon dont cela pourrait être fait sans lui, mais ce code a également été écrit très rapidement, ce n'est donc pas le code le plus optimisé.

const x = function() {
  return new Promise(resolve => {
    resolve('it resolved ma!');
  });
};

const y = function() {
  const self = this;
  return new Promise((resolve, reject) => {
    reject("reject");
  });
};

const z = function() {
  const self = this;
  return new Promise((resolve, reject) => {
    resolve("never gets executed");
  });
};

function runPromises(promises) {
  const results = [];
  let count = 0;
  const executePromise = i => {
    count++;
    return promises[i]()
      .then((response) => {
        results.push(response);
        if (count !== promises.length) {
          executePromise(count);
        }
      })
      .catch((e) => {
        results.push(e);
        console.log("stop right now, thank you very much");
      });
  };
  if (Array.isArray(promises)) {
    executePromise(count);
  }
  return results;
}

const results = runPromises([x, y, z]);
console.log(results);


0 commentaires