Annuler la vanille, ECMAScript 6 Promesse de la chaîne d'
Est-il une méthode pour effacer le .then
s de JavaScript Promise
exemple?
J'ai écrit un script JavaScript framework de test sur le dessus de QUnit. Le cadre d'exécuter des tests de manière synchrone en cours d'exécution, chacune dans un Promise
. (Désolé pour la longueur de ce bloc de code. J'ai commenté du mieux que je peux, de sorte qu'il se sent moins fastidieuse.)
/* Promise extension -- used for easily making an async step with a
timeout without the Promise knowing anything about the function
it's waiting on */
$$.extend(Promise, {
asyncTimeout: function (timeToLive, errorMessage) {
var error = new Error(errorMessage || "Operation timed out.");
var res, //resolve()
rej, //reject()
t, //timeout instance
rst, //reset timeout function
p, //the promise instance
at; //the returned asyncTimeout instance
function createTimeout(reject, tempTtl) {
return setTimeout(function () {
//triggers a timeout event on the asyncTimeout object so that,
//if we want, we can do stuff outside of a .catch() block
//(may not be needed?)
$$(at).trigger("timeout");
reject(error);
}, tempTtl || timeToLive);
}
p = new Promise(function (resolve, reject) {
if (timeToLive != -1) {
t = createTimeout(reject);
//reset function -- allows a one-time timeout different
// from the one original specified
rst = function (tempTtl) {
clearTimeout(t);
t = createTimeout(reject, tempTtl);
}
} else {
//timeToLive = -1 -- allow this promise to run indefinitely
//used while debugging
t = 0;
rst = function () { return; };
}
res = function () {
clearTimeout(t);
resolve();
};
rej = reject;
});
return at = {
promise: p,
resolve: res,
reject: rej,
reset: rst,
timeout: t
};
}
});
/* framework module members... */
test: function (name, fn, options) {
var mod = this; //local reference to framework module since promises
//run code under the window object
var defaultOptions = {
//default max running time is 5 seconds
timeout: 5000
}
options = $$.extend({}, defaultOptions, options);
//remove timeout when debugging is enabled
options.timeout = mod.debugging ? -1 : options.timeout;
//call to QUnit.test()
test(name, function (assert) {
//tell QUnit this is an async test so it doesn't run other tests
//until done() is called
var done = assert.async();
return new Promise(function (resolve, reject) {
console.log("Beginning: " + name);
var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
$$(at).one("timeout", function () {
//assert.fail() is just an extension I made that literally calls
//assert.ok(false, msg);
assert.fail("Test timed out");
});
//run test function
var result = fn.call(mod, assert, at.reset);
//if the test returns a Promise, resolve it before resolving the test promise
if (result && result.constructor === Promise) {
//catch unhandled errors thrown by the test so future tests will run
result.catch(function (error) {
var msg = "Unhandled error occurred."
if (error) {
msg = error.message + "\n" + error.stack;
}
assert.fail(msg);
}).then(function () {
//resolve the timeout Promise
at.resolve();
resolve();
});
} else {
//if test does not return a Promise, simply clear the timeout
//and resolve our test Promise
at.resolve();
resolve();
}
}).then(function () {
//tell QUnit that the test is over so that it can clean up and start the next test
done();
console.log("Ending: " + name);
});
});
}
Si un temps de test, mon délai d'attente Promesse assert.fail()
sur le test, alors que le test est considérée comme un échec, ce qui est bien et bon, mais le test continue à s'exécuter parce que le test de la Promesse (result
) est toujours en attente de le résoudre.
J'ai besoin d'un bon moyen d'annuler mon test. Je peux le faire par la création d'un champ dans le cadre du module this.cancelTest
ou quelque chose, et en vérifiant de temps en temps (par exemple au début de chaque then()
itération) dans le test qu'à s'annuler. Cependant, dans l'idéal, je pourrais utiliser $$(at).on("timeout", /* something here */)
pour effacer le reste then()
s sur mon result
variable, de sorte que rien de tout le reste du test est exécuté.
Fait quelque chose comme ça existent?
Mise À Jour Rapide
J'ai essayé d'utiliser Promise.race([result, at.promise])
. Il n'a pas de travail.
Mise à jour 2 + confusion
Pour débloquer moi, j'ai ajouté quelques lignes avec la mod.cancelTest
et d'interrogation dans le test idée. (J'ai également supprimé l'événement déclencheur.)
return new Promise(function (resolve, reject) {
console.log("Beginning: " + name);
var at = Promise.asyncTimeout(options.timeout, "Test timed out.");
at.promise.catch(function () {
//end the test if it times out
mod.cancelTest = true;
assert.fail("Test timed out");
resolve();
});
//...
}).then(function () {
//tell QUnit that the test is over so that it can clean up and start the next test
done();
console.log("Ending: " + name);
});
J'ai mis un point d'arrêt dans le catch
déclaration, et il est frappé. Ce qui est déroutant moi, c'est maintenant que le then()
déclaration n'est pas appelé. Des idées?
Mise à jour 3
Pensé que le dernier truc. fn.call()
a été de lancer une erreur que je n'ai pas de capture, de sorte que le test de la promesse était de rejet avant at.promise.catch()
pourrait le résoudre.
- Il est possible de faire une annulation ES6 promesses, mais il n'est pas une propriété de la promesse (plutôt - c'est une propriété de la fonction qui retourne) je peux faire un court exemple, si vous êtes intéressés.
- Je sais, ça fait près d'un an, mais je suis toujours intéressé si vous avez le temps d'écrire un exemple. 🙂
- Cela fait un an mais il a été officiellement discutée deux jours avant-hier avec des jetons d'annulation et de résiliation des promesses de déménagement à l'étape 1.
- L'ES6 réponse à l'annulation d'une Promesse est Observable. Vous pouvez lire plus à ce sujet ici : github.com/Reactive-Extensions/RxJS
- Reliant ma réponse sur l'utilisation de la
Prex
bibliothèque pour la promesse d'annulation.
Vous devez vous connecter pour publier un commentaire.
Pas. Pas dans ECMAScript 6 au moins. Promesses (et leurs
then
gestionnaires) sont uncancellable par défaut (malheureusement). Il y a un peu de discussion sur es-discuter (par exemple ici) sur la façon de faire de la bonne façon, mais quelle que soit l'approche va gagner, il ne sera pas terre dans l'ES6.L'actuel point de vue est que sous-classement permettra de créer résiliable promesses à l'aide de votre propre mise en œuvre (je ne sais pas comment ça va marcher).
Jusqu'à ce que la langue comité a trouvé le meilleur moyen (ES7 heureusement?) vous pouvez toujours utiliser userland Promesse implémentations, dont beaucoup disposent d'annulation.
Discussion en cours est dans la https://github.com/domenic/cancelable-promise et https://github.com/bergus/promise-cancellation les courants d'air.
Promise
conception de la chaîne. Lorsque je compose fonctions normales, je n'ai jamais ressenti le besoin de sortir au début de la composition. DepuisPromise
chaînes sont juste des compositions de non-blocage des fonctions...kill
, et d'ignorer à ce que, éventuellement, bizarre état les effets secondaires sont à gauche de votre environnement (donc, en général, vous venez de jeter ainsi, par exemple, tout à moitié fini les sorties). Non-bloquant ou asynchrone fonctions sont cependant conçu pour fonctionner dans des applications interactives, où vous voulez avoir ce genre de plus de contrôle sur l'exécution des opérations en cours.Alors qu'il n'y a pas un moyen standard de le faire dans l'ES6, il y a une bibliothèque appelée Bluebird pour gérer cela.
Il est également recommandé manière décrite dans le cadre de la réagir la documentation. Il ressemble à ce que vous avez dans votre 2 et 3ème mises à jour.
Prises à partir de: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
Je suis vraiment surpris que personne ne mentionne
Promise.race
comme un candidat pour cette:cancel()
produira toujours dans le journal que l'on appelle. `` const actualPromise = nouvelle Promesse((résoudre, rejeter) => { setTimeout(() => { console.log ("réel appelé'); résoudre() }, 10000) }); ``then
s à être exécuté), pas comment annulersetTimeout
(=>clearTimeout
) ou du code synchrone, où, à moins de mettre une si après chaque ligne (if (canceled) return
) ce ne peut pas être atteint. (Ne pas faire)Utilisation:
Il y a quelques mnp bibliothèques pour résiliable promesses.
p résiliables
https://github.com/sindresorhus/p-cancelable
annulable-promesse
https://github.com/alkemics/CancelablePromise
Il est effectivement impossible d'arrêter l'exécution de la promesse, mais vous pouvez détourner le rejeter et de l'appeler à partir de la promesse elle-même.
Utilisation:
version simple:
juste donner le rejeter fonction.
un wraper solution (d'usine)
la solution que j'ai trouvé est de passer un cancel_holder objet. il aura une fonction de suppression. si il a une fonction de suppression puis il est annulable.
Cette fonction annuler rejette la promesse avec l'Erreur ("annulé").
Avant de résoudre, de rejeter ou d'on_cancel empêcher de la fonction annuler pour être appelé sans raison.
J'ai trouvé commode de passer à l'action d'annulation par injection
Si vous souhaitez arrêter toutes les arrêtera/me met une gifle à partir de cours d'exécution, vous pouvez le faire par l'injection d'une promesse qui ne sera jamais à résoudre. Il a probablement fuite de mémoire reprocusions mais il va résoudre le problème et ne devrait pas causer trop de mémoire gaspillée dans la plupart des applications.
Voici notre mise en œuvre https://github.com/permettez-moi-de-construire/cancellable-promise
Utilisé comme
qui :
catch
appelTire et commentaires bienvenus
Définir un "annulé" bien sur la Promesse de signal
then()
etcatch()
de sortie précoce. C'est très efficace, surtout dans le Web des Travailleurs qui ont déjà des microtasks en file d'attente dans les Promesses deonmessage
gestionnaires.JS:
@Michael Yagudaev 's réponse qui fonctionne pour moi.
Mais la réponse originale à cette question n'est pas de la chaîne de la enveloppé promesse avec .catch() pour gérer les rejeter la manipulation, voici mon amélioration sur le dessus de @Michael Yagudaev réponse:
Si p est une variable qui contient une Promesse, puis
p.then(empty);
de rejeter la promesse lorsqu'elle sera finalement terminée ou si elle est déjà terminée (oui, je sais que ce n'est pas la question d'origine, mais c'est ma question). "vide" estfunction empty() {}
. Je suis un débutant et sans doute tort, mais ces autres réponses semblent trop compliquées. Les promesses sont censé être simple.Essayer promesse-abortable: https://www.npmjs.com/package/promise-abortable