¿Existe algún método para borrar los .then
mensajes de correo Promise
electrónico de una instancia de JavaScript ?
Escribí un marco de prueba de JavaScript sobre QUnit . El marco ejecuta pruebas de forma sincrónica ejecutando cada una en un Promise
. (Perdón por la longitud de este bloque de código. Lo comenté lo mejor que pude, para que se sienta menos tedioso).
/* 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 se agota el tiempo de espera de una prueba, mi Promesa de tiempo de espera estará assert.fail()
en la prueba para que la prueba se marque como fallida, lo cual está muy bien, pero la prueba continúa ejecutándose porque la Promesa de prueba ( result
) todavía está esperando para resolverla.
Necesito una buena forma de cancelar mi prueba. Puedo hacerlo creando un campo en el módulo de marco this.cancelTest
o algo, y verificando de vez en cuando (por ejemplo, al comienzo de cada then()
iteración) dentro de la prueba si debo cancelar. Sin embargo, idealmente, podría usar $$(at).on("timeout", /* something here */)
para borrar los then()
s restantes en mi result
variable, de modo que no se ejecute nada del resto de la prueba.
Existe algo como esto?
Actualización rápida
Intenté usar Promise.race([result, at.promise])
. No funcionó.
Actualización 2 + confusión
Para desbloquearme, agregué algunas líneas con mod.cancelTest
/ polling dentro de la idea de prueba. (También eliminé el activador de eventos).
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);
});
Establecí un punto de quiebre en la catch
declaración y está siendo golpeado. Lo que me confunde ahora es que then()
no se está llamando a la declaración. Ideas?
Actualización 3
Descubrí la última cosa. fn.call()
estaba arrojando un error que no capté, por lo que la promesa de prueba se rechazó antes de que at.promise.catch()
pudiera resolverlo.
Prex
biblioteca para la cancelación de promesas.