Vous pouvez enchaîner une nouvelle promesse sur la précédente, retardant ainsi sa résolution finale jusqu'à ce que vous connaissiez la réponse finale. Si la réponse suivante n'est toujours pas connue, enchaînez une autre promesse dessus et continuez à enchaîner checkStatus() sur elle-même jusqu'à ce que vous connaissiez finalement la réponse et puissiez renvoyer la résolution finale. Cela pourrait fonctionner comme ceci :
function delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
function checkStatus() {
return work.requestStatus().then(function(result) {
switch(result.status) {
case "success":
return result; // résoudre
case "failure":
throw result; // rejeter
case default:
case "inProgress": //vérifier chaque seconde
return delay(1000).then(checkStatus);
}
});
}
work.create()
.then(work.publish) //soumission du travail à distance
.then(checkStatus)
.then(function(){console.log("travail publié"})
.catch(console.error);
À noter, j'ai également évité de créer la promesse autour de votre instruction switch
. Étant donné que vous êtes déjà dans un gestionnaire .then()
, simplement retourner une valeur est une résolution, jeter une exception est un rejet et retourner une promesse consiste à enchaîner une nouvelle promesse sur la précédente. Cela couvre les trois branches de votre instruction switch
sans créer de nouvelle promesse à l'intérieur. Pour plus de commodité, j'utilise une fonction delay()
basée sur une promesse.
Pour information, cela suppose que work.requestStatus()
n'a pas besoin d'arguments spécifiques. Si des arguments spécifiques sont nécessaires, vous pouvez les passer au moment de l'appel de la fonction.
Il pourrait également être utile de mettre en place une sorte de valeur de temporisation pour savoir combien de temps vous allez boucler en attendant la fin, pour que cela ne dure jamais éternellement. Vous pourriez ajouter la fonctionnalité de temporisation de la manière suivante :
function delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
function checkStatus(temporisation) {
var début = Date.now();
function vérifier() {
var maintenant = Date.now();
if (maintenant - début > temporisation) {
return Promise.reject(new Error("Délai dépassé pour checkStatus()"));
}
return work.requestStatus().then(function(result) {
switch(result.status) {
case "success":
return result; // résoudre
case "failure":
throw result; // rejeter
case default:
case "inProgress": //vérifier chaque seconde
return delay(1000).then(verify);
}
});
}
return vérifier;
}
work.create()
.then(work.publish) //soumission du travail à distance
.then(checkStatus(120 * 1000))
.then(function(){console.log("travail publié"})
.catch(console.error);
Je ne suis pas sûr exactement du "patron de conception" que vous recherchez. Comme vous semblez vous opposer à la fonction checkStatus()
déclarée de manière externe, voici une version en ligne :
work.create()
.then(work.publish) //soumission du travail à distance
.then(work.requestStatus)
.then(function() {
// réessayer jusqu'à la fin
var temporisation = 10 * 1000;
var début = Date.now();
function vérifier() {
var maintenant = Date.now();
if (maintenant - début > temporisation) {
return Promise.reject(new Error("Délai dépassé pour checkStatus()"));
}
return work.requestStatus().then(function(result) {
switch(result.status) {
case "success":
return result; // résoudre
case "failure":
throw result; // rejeter
case default:
case "inProgress": //vérifier chaque seconde
return delay(1000).then(verify);
}
});
}
return check();
}).then(function(){console.log("travail publié"})
.catch(console.error);
Un schéma de réessayage plus réutilisable qui pourrait être utilisé dans de nombreuses circonstances définirait un code externe réutilisable, mais vous semblez vous opposer à cela, donc je n'ai pas créé cette version.
Voici une autre approche qui utilise une méthode .retryUntil()
sur le Promise.prototype
comme vous l'avez demandé. Si vous voulez ajuster les détails de mise en œuvre de ceci, vous devriez pouvoir modifier cette approche générale :
// fn renvoie une promesse qui doit être remplie avec un objet
// ayant une propriété .status qui est "success" si terminé. Toute
// autre valeur pour ce statut signifie de continuer à réessayer
// Rejeter la promesse renvoyée signifie d'abandonner le traitement
// et de propager le rejet
// delay représente le nombre de ms avant de réessayer
// pas de délai avant le premier appel à la fonction de rappel
// tries est le nombre maximal de tentatives d'appel de la fonction de rappel avant de rejeter
Promise.prototype.retryUntil = function(fn, delay, tries) {
var numTries = 0;
function check() {
if (numTries >= tries) {
throw new Error("retryUntil a dépassé le nombre maximal d'essais");
}
++numTries;
return fn().then(function(result) {
if (result.status === "success") {
return result; // résoudre
} else {
return Promise.delay(delay).then(check);
}
});
}
return this.then(check);
}
if (!Promise.delay) {
Promise.delay = function(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
}
work.create()
.then(work.publish) //soumission du travail à distance
.retryUntil(function() {
return work.requestStatus().then(function(result) {
// faire rejeter cette promesse pour un échec
if (result.status === "failure") {
throw result;
}
return result;
})
}, 2000, 10).then(function() {
console.log("travail publié");
}).catch(console.error);
Je ne sais toujours pas vraiment ce que vous voulez ou ce qui, dans toutes ces approches, ne résout pas votre problème. Comme vos approches semblent toutes être du code en ligne et ne pas utiliser d'aide réutilisable, en voici une :
work.create()
.then(work.publish) //soumission du travail à distance
.then(function() {
var essais = 0, maxEssais = 20;
function suivant() {
if (essais > maxEssais) {
throw new Error("Trop de réessais dans work.requestStatus");
}
++essais;
return work.requestStatus().then(function(result) {
switch(result.status) {
case "success":
return result;
case "failure":
// s'il échoue, faire rejeter cette promesse
throw result;
default:
// pour tout le reste, réessayer après un court délai
// enchaîner à la promesse précédente
return Promise.delay(2000).then(suivant);
}
});
}
return suivant();
}).then(function(){
console.log("travail publié")
}).catch(console.error);
0 votes
Pas sûr de ce que le
setInterval
accomplira à l'intérieur de la promesse, où est-il résolu ?0 votes
@jfriend, qu'est-il arrivé à la réponse, pourquoi a-t-elle été supprimée?
1 votes
Ne "edits" n'ajoutez pas à votre question. Cela rend difficile à suivre. Au lieu de cela, modifiez simplement votre question. Si quelqu'un veut consulter l'historique des modifications, alors il le peut.
0 votes
Voir stackoverflow.com/questions/37993365/retry-a-promise-step/….
0 votes
Je pense à supprimer cela et à commencer quelque chose de nouveau. Beaucoup de choses se sont éclaircies pendant le processus.
0 votes
@torazaburo votre réponse n'est pas ce dont j'ai besoin, elle utilise des fonctions externes qui sont dispersées dans le code. Veuillez rouvrir, j'essaie de trouver un motif ici, pas une réponse typique. De plus, ces réponses n'améliorent en rien mon code.
0 votes
@torazaburo veuillez noter l'interface sophistiquée et propre/utilisée pour le Code #1 dans ma question
0 votes
Dans le code #2, si
collection.requestStatus(result)
est rejetée, vous ne faites rien - elle bouclera indéfiniment. Si elle rencontre une sorte d'erreur récurrente, vous ne résoudrez jamais ou ne rejetterez jamais. Si quelque chose lance une erreur dans votre gestionnairecollection.requestStatus(result).then()
, personne ne la capture nulle part. Les rejets inattendus doivent être renvoyés pour qu'ils puissent être gérés.0 votes
@jfriend00 super. Merci pour l'aide sur cela, j'ai corrigé. tout est ok pour #2 s'il vous plaît?
0 votes
Votre échec à gérer
.catch()
est l'ERREUR exacte qui est souvent commise lors de la création de votre propre nouvelle promesse plutôt que de simplement la chaîner à une précédente. C'est exactement pourquoi il n'est pas recommandé de créer une nouvelle promesse quand vous n'en avez pas vraiment besoin. J'ai déjà été à votre place. Vous pensez que c'est plus simple. Mais, ce n'est pas meilleur (c'est beaucoup plus sujet aux erreurs) et une fois que vous êtes plus à l'aise avec les chaînages, ce n'est même pas plus simple.0 votes
Dans le n°2, si vous utilisez
.catch(reject)
, vous ne stoppez pas votre intervalle.0 votes
Dans #2, vous ne semblez rien faire avec le résultat de
.then(work.getStatus)
. Je ne peux pas dire pourquoi il est même là.0 votes
Je comprends ce que vous dites sur la chaînage des promesses précédentes, et j'ai effectivement constaté les avantages de la chaînage des promesses existantes tout en travaillant sur ce projet. Je sais que vous m'avez écrit plusieurs fois mais j'espère pouvoir m'exprimer maintenant et que vous comprenez ce que je recherche, veuillez apporter des modifications à votre réponse si nécessaire. et merci d'avoir signalé l'erreur d'intervalle. oui, cela ne s'arrêtera pas.
0 votes
Vous pouvez ignorer work.getStatus, c'est un appel API pour obtenir essentiellement le statut de publication, un appel séparé après la publication, mais vous pouvez l'ignorer. Je suis seulement intéressé par la répétition de la manière la plus compacte sans regarder ailleurs.
7 votes
Cela ressemble à une réponse. Y a-t-il une question?
0 votes
Les modifications ultérieures étaient en fait mes tentatives pour arriver à une solution.
0 votes
@user2727195: S'il vous plaît envisagez d'obtenir un nom d'utilisateur significatif.
0 votes
Vraiment, je pense que cette question doit avoir le corps de la question d'origine en haut et les éditions, le cas échéant, ajoutées en bas. Je ne sais pas si le code affiché est la question, la réponse, des tentatives de réponse par l'auteur, ou des réponses fournies par la communauté ajoutées à l'originale.