javascript - tiempo - Espere hasta que una Función con animaciones finalice hasta ejecutar otra Función
setinterval javascript (8)
Tengo un problema con las funciones normales (que no son Ajax ) que implican muchas animaciones dentro de cada una de ellas. Actualmente simplemente tengo un setTimeout
entre funciones, pero esto no es perfecto ya que ningún navegador / computadora es el mismo.
Nota adicional: ambos tienen animaciones separadas / etc. que colisionan.
No puedo simplemente poner uno en la función de devolución de llamada de otro
// multiple dom animations / etc
FunctionOne();
// What I -was- doing to wait till running the next function filled
// with animations, etc
setTimeout(function () {
FunctionTwo(); // other dom animations (some triggering on previous ones)
}, 1000);
¿Hay alguna forma en js / jQuery de tener:
// Pseudo-code
-do FunctionOne()
-when finished :: run -> FunctionTwo()
Sé acerca de $.when()
y $.done()
, pero esos son para AJAX ...
- MI SOLUCIÓN ACTUALIZADA
jQuery tiene una variable expuesta (que por algún motivo no figura en ninguna parte de los documentos jQuery) llamada $ .timers, que contiene la matriz de animaciones que se está llevando a cabo actualmente.
function animationsTest (callback) {
// Test if ANY/ALL page animations are currently active
var testAnimationInterval = setInterval(function () {
if (! $.timers.length) { // any page animations finished
clearInterval(testAnimationInterval);
callback();
}
}, 25);
};
Uso básico:
// run some function with animations etc
functionWithAnimations();
animationsTest(function () { // <-- this will run once all the above animations are finished
// your callback (things to do after all animations are done)
runNextAnimations();
});
Esta respuesta usa promises
, una característica de JavaScript del estándar ECMAScript 6
. Si su plataforma objetivo no es compatible con las promises
, PromiseJs con PromiseJs .
Puede obtener el objeto Deferred
que jQuery crea para la animación utilizando .promise()
en la llamada de animación. Envolver estos Deferreds
en promises da como resultado un código mucho más limpio que el uso de temporizadores.
También puede usar Deferreds
directamente, pero esto generalmente se desalienta porque no cumplen con la especificación Promises / A +.
El código resultante sería así:
var p1 = Promise.resolve($(''#Content'').animate({ opacity: 0.5 }, { duration: 500, queue: false }).promise());
var p2 = Promise.resolve($(''#Content'').animate({ marginLeft: "-100px" }, { duration: 2000, queue: false }).promise());
Promise.all([p1, p2]).then(function () {
return $(''#Content'').animate({ width: 0 }, { duration: 500, queue: false }).promise();
});
Tenga en cuenta que la función en Promise.all()
devuelve la promesa. Aquí es donde sucede la magia. Si en una llamada en then
se devuelve una promesa, la siguiente llamada esperará a que esa promesa se resuelva antes de ejecutarse.
jQuery usa una cola de animación para cada elemento. Entonces, las animaciones en el mismo elemento se ejecutan sincrónicamente. ¡En este caso no tendrías que usar promesas en absoluto!
Inhabilité la cola de animación jQuery para demostrar cómo funcionaría con las promesas.
Promise.all()
toma una serie de promesas y crea una nueva Promise
que finaliza después de que finalicen todas las promesas en la matriz.
Promise.race()
también toma una serie de promesas, pero termina tan pronto como termina la primera Promise
.
Aquí hay una solución para n-calls (función recursiva). https://jsfiddle.net/mathew11/5f3mu0f4/7/
function myFunction(array){
var r = $.Deferred();
if(array.length == 0){
r.resolve();
return r;
}
var element = array.shift();
// async task
timer = setTimeout(function(){
$("a").text($("a").text()+ " " + element);
var resolving = function(){
r.resolve();
}
myFunction(array).done(resolving);
}, 500);
return r;
}
//Starting the function
var myArray = ["Hi", "that''s", "just", "a", "test"];
var alerting = function (){window.alert("finished!")};
myFunction(myArray).done(alerting);
Esto es lo que quieres decir con el hombre: http://jsfiddle.net/LF75a/
Tendrás una función activando la siguiente función y así sucesivamente, es decir, agrega otra llamada a función y luego agrega tu functionONe
en la parte inferior.
Por favor déjame saber si me he perdido algo, espero que se ajuste a la causa :)
o esto: Llamar a una función después de que se haya completado la función anterior
Código:
function hulk()
{
// do some stuff...
}
function simpsons()
{
// do some stuff...
hulk();
}
function thor()
{
// do some stuff...
simpsons();
}
Junto con la respuesta de Yoshi, encontré otra solución muy simple (tipo de devolución de llamada) para animaciones.
jQuery tiene una variable expuesta (que por algún motivo no figura en ninguna parte de los documentos jQuery) llamada $ .timers , que contiene la matriz de animaciones que se está llevando a cabo actualmente.
function animationsTest (callback) {
// Test if ANY/ALL page animations are currently active
var testAnimationInterval = setInterval(function () {
if (! $.timers.length) { // any page animations finished
clearInterval(testAnimationInterval);
callback();
}
}, 25);
};
Uso básico:
functionOne(); // one with animations
animationsTest(functionTwo);
Espero que esto ayude a algunas personas!
Puede usar jQuery $.Deferred
var FunctionOne = function () {
// create a deferred object
var r = $.Deferred();
// do whatever you want (e.g. ajax/animations other asyc tasks)
setTimeout(function () {
// and call `resolve` on the deferred object, once you''re done
r.resolve();
}, 2500);
// return the deferred object
return r;
};
// define FunctionTwo as needed
var FunctionTwo = function () {
console.log(''FunctionTwo'');
};
// call FunctionOne and use the `done` method
// with `FunctionTwo` as it''s parameter
FunctionOne().done(FunctionTwo);
también puedes empacar múltiples diferidos juntos:
var FunctionOne = function () {
var
a = $.Deferred(),
b = $.Deferred();
// some fake asyc task
setTimeout(function () {
console.log(''a done'');
a.resolve();
}, Math.random() * 4000);
// some other fake asyc task
setTimeout(function () {
console.log(''b done'');
b.resolve();
}, Math.random() * 4000);
return $.Deferred(function (def) {
$.when(a, b).done(function () {
def.resolve();
});
});
};
Puedes hacerlo a través de la función de devolución de llamada.
$(''a.button'').click(function(){
if (condition == ''true''){
function1(someVariable, function() {
function2(someOtherVariable);
});
}
else {
doThis(someVariable);
}
});
function function1 (param, callback) {... hacer cosas callback (); }
agregue lo siguiente al final de la primera función
return $.Deferred().resolve();
llamar a ambas funciones como tal
functionOne().done(functionTwo);
ACTUALIZACIÓN DE ECMAScript 6
Esto usa una nueva característica de JavaScript llamada Promises
functionOne (). then (functionTwo);