¿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.
fuente
Prex
biblioteca para la cancelación de promesas.Respuestas:
No. No en ECMAScript 6 al menos. Las promesas (y sus
then
manejadores) no se pueden cancelar de forma predeterminada (desafortunadamente) . Hay un poco de discusión en es-discusion (por ejemplo, aquí ) sobre cómo hacer esto de la manera correcta, pero cualquier enfoque que gane no aterrizará en ES6.El punto de vista actual es que la subclasificación permitirá crear promesas cancelables utilizando su propia implementación (no estoy seguro de qué tan bien funcionará) .
Hasta que el comité de idiomas haya descubierto la mejor manera (¿ES7 con suerte?) , Aún puede usar las implementaciones de promesas de usuario, muchas de las cuales incluyen la cancelación.
La discusión actual se encuentra en los borradores https://github.com/domenic/cancelable-promise y https://github.com/bergus/promise-cancellation .
fuente
kill
lo ignora e ignora el estado posiblemente extraño en el que los efectos secundarios han dejado su entorno (por lo que normalmente también lo desecha, por ejemplo, cualquier salida a medio terminar). Sin embargo, las funciones no bloqueantes o asíncronas están diseñadas para funcionar en aplicaciones interactivas, en las que desea tener ese tipo de control más preciso sobre la ejecución de operaciones en curso.Si bien no existe una forma estándar de hacer esto en ES6, existe una biblioteca llamada Bluebird para manejar esto.
También hay una forma recomendada que se describe como parte de la documentación de reacción. Es similar a lo que tiene en sus actualizaciones 2 y 3.
Tomado de: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
fuente
Realmente me sorprende que nadie mencione
Promise.race
como candidato para esto:fuente
cancel()
seguirá provocando que se llame al registro. `` `const actualPromise = new Promise ((resolver, rechazar) => {setTimeout (() => {console.log ('actual llamado'); resolve ()}, 10000)}); ``then
la ejecución de s encadenados ), no cómo cancelarsetTimeout
(=>clearTimeout
) o código síncrono, donde, a menos que ponga un if después de cada línea (if (canceled) return
), esto no se puede lograr. (No hagas esto)Uso:
fuente
En realidad, es imposible detener la ejecución de la promesa, pero puede secuestrar el rechazo y llamarlo de la promesa misma.
Uso:
fuente
Hay algunas bibliotecas npm para promesas cancelables.
p-cancelable https://github.com/sindresorhus/p-cancelable
promesa cancelable https://github.com/alkemics/CancelablePromise
fuente
Aquí está nuestra implementación https://github.com/permettez-moi-de-construire/cancellable-promise
Usado como
cual :
catch
llamadaSe aceptan extracciones y comentarios
fuente
La promesa se puede cancelar con la ayuda de
AbortController
.Ejemplo:
HTML
Ejemplo en vivo
fuente
versión simple :
simplemente dé la función de rechazo.
una solución de envoltura (fábrica)
la solución que encontré es pasar un objeto cancel_holder. tendrá una función de cancelación. si tiene una función de cancelación, entonces es cancelable.
Esta función de cancelación rechaza la promesa con Error ('cancelado').
Antes de resolver, rechazar u on_cancel, evite que se llame a la función de cancelación sin motivo.
Me ha parecido conveniente pasar la acción de cancelar por inyección
fuente
Pruebe la promesa abortable : https://www.npmjs.com/package/promise-abortable
fuente
Si su código se coloca en una clase, podría usar un decorador para eso. Tienes dicho decorador en utils-decorators (
npm install --save utils-decorators
). Cancelará la invocación anterior del método decorado si antes de la resolución de la llamada anterior se realizó otra llamada para ese método específico.https://github.com/vlio20/utils-decorators#cancelprevious-method
fuente
Si desea evitar que se ejecuten todos los thens / catchs, puede hacerlo inyectando una promesa que nunca se resolverá. Probablemente tenga reproches de pérdida de memoria, pero solucionará el problema y no debería causar demasiada memoria desperdiciada en la mayoría de las aplicaciones.
fuente
Establezca una propiedad "cancelada" en el Promise para señalar
then()
ycatch()
salir temprano. Es muy eficaz, especialmente en los Web Workers que tienen microtareas existentes en cola en Promesas de losonmessage
administradores.fuente
La respuesta de @Michael Yagudaev funciona para mí.
Pero la respuesta original no encadenó la promesa envuelta con .catch () para manejar el manejo de rechazos, aquí está mi mejora además de la respuesta de @Michael Yagudaev:
fuente
Si p es una variable que contiene una Promesa, entonces
p.then(empty);
debería descartar la promesa cuando finalmente se complete o si ya está completa (sí, sé que esta no es la pregunta original, pero es mi pregunta). "vacío" esfunction empty() {}
. Soy solo un principiante y probablemente estoy equivocado, pero estas otras respuestas parecen demasiado complicadas. Se supone que las promesas son simples.fuente
Todavía estoy trabajando en esta idea, pero así es como he implementado una Promesa cancelable usando
setTimeout
como ejemplo.La idea es que una promesa se resuelva o rechace siempre que tú lo hayas decidido, por lo que debería ser cuestión de decidir cuándo quieres cancelar, cumplir el criterio y luego llamar
reject()
tú mismo a la función.Primero, creo que hay dos razones para terminar una promesa antes de tiempo: terminarla (que he llamado resolver ) y cancelar (que he llamado rechazar ). Por supuesto, ese es solo mi sentimiento. Por supuesto que hay un
Promise.resolve()
método, pero está en el propio constructor y devuelve una promesa resuelta ficticia. Esteresolve()
método de instancia realmente resuelve un objeto de promesa instanciado.En segundo lugar, se puede añadir nada felizmente te gusta a un objeto de la promesa de nueva creación antes de devolverlo, y por lo que acaba de agregar
resolve()
yreject()
métodos para que sea autónomo.En tercer lugar, el truco es poder acceder al ejecutor
resolve
y lasreject
funciones más tarde, así que simplemente las he almacenado en un objeto simple desde dentro del cierre.Creo que la solución es simple y no veo ningún problema importante en ella.
fuente