Abbrechen einer Vanille-ECMAScript 6 Versprechen Kette
Gibt es eine Methode zum löschen der .then
s eine JavaScript - Promise
Instanz?
Ich geschrieben habe, eine JavaScript-test-framework auf der Oberseite der QUnit. Das framework führt tests synchron laufen jeweils in einem Promise
. (Sorry für die Länge von diesem code-block. Ich kommentierte es, so gut ich kann, so fühlt es sich weniger langweilig.)
/* 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);
});
});
}
Wenn ein test mal aus, mein timeout Versprechen wird assert.fail()
auf den test, so dass der test als fehlgeschlagen markiert, das ist alles schön und gut, aber der test läuft weiter, weil die Tests Versprechen (result
) ist immer noch darauf warten, ihn zu beheben.
Ich brauche einen guten Weg zu meinen test. Ich kann es tun, indem Sie erstellen ein Feld auf der framework-Modul this.cancelTest
oder so etwas, und die überprüfung jeder so oft (z.B. am Anfang jedes then()
iteration) innerhalb der test, ob zu Abbrechen. Jedoch, im Idealfall, die ich verwenden könnte $$(at).on("timeout", /* something here */)
zu deaktivieren Sie die übrigen then()
s auf meinem result
variable, so dass keiner von den rest der der test durchgeführt wird.
Macht soetwas existieren?
Schnelle Aktualisierung
Versuchte ich mit Promise.race([result, at.promise])
. Es hat nicht funktioniert.
Update 2 + Verwirrung
Entsperren zu mir, ich habe ein paar Zeilen mit der mod.cancelTest
/polling in die test-Idee. (Ich habe auch entfernt die Ereignis-trigger.)
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);
});
Ich einen Haltepunkt in die catch
- Anweisung, und es ist getroffen zu werden. Was verwirrt mich ist jetzt, dass die then()
- Anweisung nicht aufgerufen wird. Ideen?
Update 3
Dachte die Letzte Sache aus. fn.call()
warf eine Fehlermeldung, die ich nicht fangen, so dass der test Versprechen war die Ablehnung vor at.promise.catch()
konnte es lösen.
- Es ist möglich, das zu tun Stornierung mit ES6 Versprechen, aber es ist nicht eine Eigenschaft der Versprechen (eher - es ist eine Eigenschaft der Funktion, die gibt es), kann ich ein kurzes Beispiel wenn Sie interessiert sind.
- Ich weiß, es ist schon fast ein Jahr, aber ich bin immer noch daran interessiert, wenn Sie die Zeit haben, schreiben Sie ein Beispiel. 🙂
- Es ist schon ein Jahr her, aber es wurde offiziell diskutiert, zwei Tage vor gestern mit Kündigung Token und verbindlich verspricht übergang zu Stadium 1.
- Das ES6 Antwort auf die Absage eines Versprechen Beobachtbar ist. Lesen Sie mehr über dieses hier : github.com/Reactive-Extensions/RxJS
- Linking meine Antwort auf mit der
Prex
Bibliothek für Versprechen Stornierung.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nicht. Nicht in ECMAScript 6 mindestens. Verspricht (und Ihre
then
Handler) sind uncancellable standardmäßig (leider). Es ist ein bisschen Diskussion über es-diskutieren (z.B. hier), wie Sie dies in der richtigen Weise, aber, was Ansatz wird es gewinnen nicht landen in ES6.Heutiger Sicht ist, dass Unterklassen erlauben wird, zu erstellen, kündbar verspricht mit Ihrer eigenen Umsetzung (nicht sicher, wie gut das klappt).
Bis die Sprache Komitee hat herausgefunden, der beste Weg (ES7 hoffentlich?) dennoch kann man die userland-Versprechen-Implementierungen, von denen viele über die Stornierung.
Aktuellen Diskussion wird in den https://github.com/domenic/cancelable-promise und https://github.com/bergus/promise-cancellation Entwürfe.
Promise
chain design. Wenn ich komponiere normalen Funktionen hab ich nie das Bedürfnis hatte, auszubrechen Anfang der Komposition. DaPromise
Ketten sind nur Zusammensetzungen von nicht-blockierende Funktionen...kill
es und ignorieren, was vielleicht seltsam Zustand, die Nebenwirkungen haben, verlassen Sie Ihre Umgebung (so Sie in der Regel nur werfen Sie Weg, dass z.B. jeder die Hälfte-fertigen-Ausgänge). Nicht-blockierende oder asynchrone Funktionen sind jedoch errichtet, um in interaktiven Anwendungen, wo Sie wollen, dass solche feinere Kontrolle über die Ausführung der Laufenden Geschäfte.Während es gibt keine standard-Weg, dies zu tun, in ES6, es gibt eine Bibliothek namens Bluebird, um diese zu bewältigen.
Es ist auch eine empfohlene Art und Weise beschrieben, als Teil reagieren die Dokumentation. Es sieht ähnlich aus wie das, was Sie in Ihre 2 und 3. updates.
Entnommen aus: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
Ich bin wirklich überrascht, dass niemand erwähnt
Promise.race
als Kandidat:cancel()
führen, die im Protokoll genannt werden. `` const actualPromise = new Promise((auflösen, ablehnen) => { setTimeout(() => { console.log('tatsächliche aufgerufen'); lösen() }, 10000) }); ``then
s ausgeführt werden), nicht, wie zu stornierensetTimeout
(=>clearTimeout
) oder synchronous code, wo es sei denn, Sie setzen Sie ein, wenn nach jeder Zeile (if (canceled) return
) dies kann nicht erreicht werden. (Tun Sie das nicht)Gibt es ein paar npm-Bibliotheken für verbindlich verspricht.
p-cancelable
https://github.com/sindresorhus/p-cancelable
stornierbar-Versprechen
https://github.com/alkemics/CancelablePromise
Verwendung:
einfache version:
nur die reject-Funktion.
ein wraper-Lösung (Fabrik)
die Lösung, die ich gefunden ist, an eine cancel_holder Objekt. es wird eine Funktion Abbrechen. wenn Sie eine Funktion Abbrechen, dann ist es stornierbar.
Diese Funktion Abbrechen verwirft die Versprechen mit Error('abgebrochen').
Bevor Sie sich auflösen, ablehnen, oder on_cancel verhindern, dass die Abbrechen-Funktion, die aufgerufen werden, ohne Grund.
Habe ich gefunden, die bequem zu passieren, der Abbruch der Aktion durch Injektion
Wenn Sie möchten, beenden Sie alle thens/catchs ausgeführt wird, können Sie dies tun, indem man ein Versprechen, das nie beheben. Vermutlich ist das memory leak reprocusions aber es wird das Problem behoben und sollte nicht dazu führen, zu viel verschwendet Speicher in den meisten Anwendungen.
Hier ist unsere Implementierung https://github.com/permettez-moi-de-construire/cancellable-promise
Verwendet, wie
welche :
catch
nennenZieht und Kommentare willkommen
Einen "abgebrochen" - Eigenschaft auf das Versprechen, signal
then()
undcatch()
vorzeitig beendet. Es ist sehr effektiv, besonders im Web-worker, die vorhandenen microtasks in der Warteschlange bis in Verspricht ausonmessage
Handler.JS:
@Michael Yagudaev 's Antwort für mich funktioniert.
Aber die original-Antwort nicht die Kette gewickelt Versprechen mit .catch() zu behandeln, abzulehnen handling, hier ist meine Verbesserung zu oben @Michael Yagudaev Antwort:
Ist p eine variable, die enthält ein Versprechen, dann
p.then(empty);
sollte, schließen Sie das Versprechen, wenn es irgendwann abgeschlossen ist oder wenn es bereits abgeschlossen ist (ja, ich weiß, das ist nicht die ursprüngliche Frage, aber es ist auch meine Frage). "leer" istfunction empty() {}
. Ich bin nur ein Anfänger und wahrscheinlich falsch, aber diese anderen Antworten scheinen zu kompliziert. Versprechen sind eigentlich ganz einfach zu sein.Versuchen Sie dies: https://github.com/dondevi/promise-abortable