70 votes

Attendre qu'une fonction avec des animations soit terminée avant d'exécuter une autre fonction

Je rencontre un problème avec les fonctions normales (non-ajax) qui impliquent de nombreuses animations dans chacune d'elles. Actuellement, j'ai simplement un setTimeout entre les fonctions, mais ce n'est pas parfait car tous les navigateurs / ordinateurs ne sont pas identiques.

Note supplémentaire : Ils ont chacun des animations/etc séparées qui entrent en collision.

Je ne peux pas simplement mettre une fonction dans la fonction de rappel d'une autre

// multiples animations du DOM / etc
FunctionOne();

// Ce que je faisais pour attendre avant d'exécuter la prochaine fonction remplie 
// d'animations, etc

setTimeout(function () { 
    FunctionTwo(); // autres animations du DOM (certaines déclenchées par les précédentes)
}, 1000); 

Y a-t-il un moyen en js/jQuery d'avoir :

// Pseudo-code
-exécuter FunctionOne()
-lorsque terminé :: exécuter -> FunctionTwo()

Je connais $.when() & $.done(), mais ceux-ci sont pour AJAX...


  • MA SOLUTION MIS À JOUR

jQuery a une variable exposée (qui pour une raison quelconque n'est répertoriée nulle part dans la documentation jQuery) appelée $.timers, qui contient le tableau des animations actuellement en cours.

function animationsTest (callback) {
    // Test si des animations de la page sont actuellement actives

    var testAnimationInterval = setInterval(function () {
        if (! $.timers.length) { // des animations de la page se sont terminées
            clearInterval(testAnimationInterval);
            callback();
        }
    }, 25);
};

Utilisation de base :

// exécuter une fonction avec des animations etc    
functionWithAnimations();

animationsTest(function () { // <-- ceci s'exécutera une fois que toutes les animations ci-dessus seront terminées

    // votre fonction de rappel (actions à effectuer après la fin de toutes les animations)
    runNextAnimations();

});

2 votes

Si FunctionOne n'a pas de timeout ou autre chose, vous pouvez simplement appeler FunctionOne(); FunctionTwo();, n'est-ce pas?

0 votes

Le problème est qu'ils ont tous les deux des animations séparées, etc, dans des fichiers différents - etc. Donc ils finissent par entrer en collision...

0 votes

@arxanas - Oui, JavaScript est monofilaire, mais je soupçonne qu'il veut enchaîner deux fonctions ensemble afin que l'une se déclenche toujours avec l'autre.

109voto

Yoshi Points 25790

Vous pouvez utiliser $.Deferred de jQuery

var FunctionOne = function () {
  // créer un objet différé
  var r = $.Deferred();

  // faites ce que vous voulez (par exemple des tâches ajax/animations ou d'autres tâches asynchrones)

  setTimeout(function () {
    // et appelez `resolve` sur l'objet différé, une fois que vous avez terminé
    r.resolve();
  }, 2500);

  // retourner l'objet différé
  return r;
};

// définir FunctionTwo selon les besoins
var FunctionTwo = function () {
  console.log('FunctionTwo');
};

// appeler FunctionOne et utiliser la méthode `done`
// avec `FunctionTwo` en paramètre
FunctionOne().done(FunctionTwo);

vous pouvez également regrouper plusieurs différés ensemble:

var FunctionOne = function () {
  var
    a = $.Deferred(),
    b = $.Deferred();

  // une tâche asynchrone fictive
  setTimeout(function () {
    console.log('a fait');
    a.resolve();
  }, Math.random() * 4000);

  // une autre tâche asynchrone fictive
  setTimeout(function () {
    console.log('b fait');
    b.resolve();
  }, Math.random() * 4000);

  return $.Deferred(function (def) {
    $.when(a, b).done(function () {
      def.resolve();
    });
  });
};

http://jsfiddle.net/p22dK/

0 votes

Comme il l'a dit, il utilise des animations, vous voudrez peut-être mentionner la méthode .promise() de jQuery pour la file d'effets.

0 votes

@Bergi Vous voulez dire que jQuery retourne un objet différé de animate? Sinon, je ne vois pas vraiment la nécessité de l'objet de promesse ici.

0 votes

Oui, je ne voulais pas dire le Deferred.promise, mais la méthode jQuery api.jquery.com/promise

13voto

quemeful Points 134

Ajoutez ce qui suit à la fin de la première fonction

return $.Deferred().resolve();

appelez les deux fonctions comme ceci

functionOne().done(functionTwo);

3voto

mcpDESIGNS Points 8521

En plus de la réponse de Yoshi, j'ai trouvé une autre solution très simple (de type rappel) pour les animations.

jQuery a une variable exposée (qui pour une raison inconnue n'est répertoriée nulle part dans la documentation de jQuery) appelée $.timers, qui contient le tableau des animations actuellement en cours.

function animationsTest (callback) {
    // Tester si DES/TOUTES les animations de la page sont actuellement actives

    var testAnimationInterval = setInterval(function () {
        if (! $.timers.length) { // toutes les animations de la page sont terminées
            clearInterval(testAnimationInterval);
            callback();
        }
    }, 25);
};

Utilisation de base:

functionOne(); // avec animations

animationsTest(functionTwo);

J'espère que cela aidera certaines personnes!

1voto

Tats_innit Points 20575

Est-ce ce que tu veux dire mon ami : http://jsfiddle.net/LF75a/

Vous aurez une fonction qui déclenchera la fonction suivante et ainsi de suite, c'est-à-dire ajouter un autre appel de fonction et ensuite ajouter votre functionONe en bas.

Veuillez me dire si j'ai oublié quelque chose, j'espère que cela convient :)

ou ceci : Appeler une fonction après que la fonction précédente soit terminée

Code:

function hulk()
{
  // faire quelque chose...
}
function simpsons()
{
  // faire quelque chose...
  hulk();
}
function thor()
{
  // faire quelque chose...
  simpsons();
}

5 votes

Callback est la réponse JS appropriée, à mon avis.

0 votes

Tout ce que j'ai est un appel de fonction. Je ne peux pas modifier la fonction, mais j'ai besoin d'exécuter mon autre fonction après que la première ait terminé.

0 votes

Je crois que cela ne fonctionnerait pas avec l'animation car elles ont tendance à avoir des retards pour fonctionner en premier lieu

-3voto

user1026361 Points 1561

Beaucoup d'options ici. Vous pouvez imbriquer la fonction comme certains l'ont suggéré. Vous pouvez l'envelopper dans un Try...catch...finally ala:

Try {
  FunctionOne()
} Finally {
  FunctionTwo()
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X