J'ai un problème avec les fonctions normales ( non-ajax ) qui impliquent de nombreuses animations dans chacune d'elles. Actuellement, j'ai simplement une setTimeout
entre les fonctions, mais ce n'est pas parfait, car aucun navigateur/ordinateur n'est identique.
Remarque supplémentaire: ils ont tous deux des animations/etc distinctes qui entrent en collision.
Je ne peux pas simplement en mettre un dans la fonction de rappel d'un autre
// 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);
Y at-il de toute façon dans js/jQuery d'avoir:
// Pseudo-code
-do FunctionOne()
-when finished :: run -> FunctionTwo()
Je connais $.when()
& $.done()
, mais ce sont pour AJAX ...
jQuery a une variable exposée ($ pour une raison quelconque qui ne figure nulle part dans les documents jQuery) appelée $ .timers, qui contient le tableau des animations en cours.
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);
};
Utilisation de base:
// 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();
});
Vous pouvez utiliser jQuery's $.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);
vous pouvez également regrouper plusieurs dossiers différés:
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();
});
});
};
ajoute ce qui suit à la fin de la première fonction
return $.Deferred().resolve();
appeler les deux fonctions comme si
functionOne().done(functionTwo);
Avec la réponse de Yoshi, j'ai trouvé une autre solution très simple (type de rappel) pour les animations.
jQuery a une variable exposée (/ pour certaines raisons ne figure pas dans les documents jQuery) appelée $ .timers , qui contient le tableau des animations en cours.
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);
};
Utilisation de base:
functionOne(); // one with animations
animationsTest(functionTwo);
J'espère que cela aide certaines personnes!
MISE À JOUR ECMAScript 6
Cela utilise une nouvelle fonctionnalité de JavaScript appelée Promises
functionOne (). then (functionTwo);
Est-ce ce que vous voulez dire, homme: http://jsfiddle.net/LF75a/
Vous aurez une fonction déclencher la fonction suivante et ainsi de suite, c’est-à-dire ajouter un autre appel de fonction, puis ajoutez votre functionONe
au bas de celui-ci.
S'il te plaît, fais-moi savoir si j'ai oublié quelque chose, j'espère que cela correspond à la cause :)
ou this: Appelle une fonction après avoir terminé la fonction précédente
Code:
function hulk()
{
// do some stuff...
}
function simpsons()
{
// do some stuff...
hulk();
}
function thor()
{
// do some stuff...
simpsons();
}
promises
, une fonctionnalité JavaScript de la norme ECMAScript 6
. Si votre plate-forme cible ne prend pas en charge promises
, remplissez-la avec PromiseJs .Vous pouvez obtenir l'objet Deferred
créé par jQuery pour l'animation à l'aide de .promise()
dans l'appel à l'animation. Envelopper ces Deferreds
dans ES6 Promises
donne un code beaucoup plus propre que l’utilisation de minuteries.
Vous pouvez également utiliser directement Deferreds
, mais cela est généralement déconseillé, car ils ne suivent pas la spécification Promises/A +.
Le code résultant ressemblerait à ceci:
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();
});
Notez que la fonction dans Promise.all()
renvoie la promesse. C'est là que la magie se produit. Si, lors d'un appel then
, une promesse est renvoyée, le prochain appel then
attendra que cette promesse soit résolue avant de s'exécuter.
jQuery utilise une file d'attente d'animation pour chaque élément. Les animations sur le même élément sont donc exécutées de manière synchrone. Dans ce cas, vous n’auriez pas à utiliser de promesses du tout!
J'ai désactivé la file d'attente d'animation jQuery pour montrer comment cela fonctionnerait avec les promesses.
Promise.all()
prend un tableau de promesses et crée un nouveau Promise
qui se termine lorsque toutes les promesses du tableau sont terminées.
Promise.race()
accepte également un éventail de promesses, mais se termine dès que le premier Promise
est terminé.
Vous pouvez utiliser les javascript Promise
et async/await
pour implémenter un appel synchronisé des fonctions.
Supposons que vous souhaitiez exécuter n
nombre de fonctions de manière synchronisée stockées dans un tableau. Voici ma solution.
async function executeActionQueue(funArray) {
var length = funArray.length;
for(var i = 0; i < length; i++) {
await executeFun(funArray[i]);
}
};
function executeFun(fun) {
return new Promise((resolve, reject) => {
// Execute required function here
fun()
.then((data) => {
// do required with data
resolve(true);
})
.catch((error) => {
// handle error
resolve(true);
});
})
};
executeActionQueue(funArray);
Vous pouvez le faire via la fonction de rappel.
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable, function() {
function2(someOtherVariable);
});
}
else {
doThis(someVariable);
}
});
function function1 (param, rappel) { ...faire des trucs rappeler();}
Voici une solution pour n-call (fonction récursive) . 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);