Abbrechen einer Vanille-ECMAScript 6 Versprechen Kette

Gibt es eine Methode zum löschen der .thens 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.
InformationsquelleAutor dx_over_dt | 2015-04-06
Schreibe einen Kommentar