web-dev-qa-db-fra.com

Appeler une fonction une fois la fonction précédente terminée

J'ai le code JavaScript suivant:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable);
        function2(someOtherVariable);
    }
    else {
        doThis(someVariable);
    }
});

Comment puis-je m'assurer que function2 n'est appelé qu'une fois que function1 est terminé?

151
Rrryyyaaannn

Spécifiez un rappel anonyme et assurez-vous que function1 l'accepte:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable, function() {
          function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
  ...do stuff
  callback();
} 
177
Mike Robinson

Si vous utilisez jQuery 1.5, vous pouvez utiliser le nouveau modèle Différé:

$('a.button').click(function(){
    if(condition == 'true'){
        $.when(function1()).then(function2());
    }
    else {
        doThis(someVariable);
    }
});

Edit: Lien de blog mis à jour:

Rebecca Murphy a écrit un excellent article à ce sujet: http://rmurphey.com/blog/2010/12/25/deferreds-coming-to-jquery/

86
philwinkle

Cette réponse utilise promises , une fonctionnalité JavaScript de la norme ECMAScript 6. Si votre plate-forme cible ne prend pas en charge promises, remplissez-la avec PromiseJs .

Les promesses constituent un moyen nouveau (et bien meilleur) de gérer les opérations asynchrones en JavaScript:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable).then(function() {
            //this function is executed after function1
            function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
    return new Promise(function (fulfill, reject){
        //do stuff
        fulfill(result); //if the action succeeded
        reject(error); //if the action did not succeed
    });
} 

Cela peut sembler une surcharge importante pour cet exemple simple, mais pour un code plus complexe, c'est beaucoup mieux que d'utiliser des rappels. Vous pouvez facilement chaîner plusieurs appels asynchrones à l'aide de plusieurs instructions then:

function1(someVariable).then(function() {
    function2(someOtherVariable);
}).then(function() {
    function3();
});

Vous pouvez également encapsuler facilement les reports de jQuery (qui sont renvoyés à partir d'appels $.ajax):

Promise.resolve($.ajax(...params...)).then(function(result) {
    //whatever you want to do after the request
});

Comme @charlietfl l'a noté, l'objet jqXHR renvoyé par $.ajax() implémente l'interface Promise. Donc, il n'est pas vraiment nécessaire de l'envelopper dans une Promise, il peut être utilisé directement:

$.ajax(...params...).then(function(result) {
    //whatever you want to do after the request
});
33
Domysee

Essaye ça :

function method1(){
   // some code

}

function method2(){
   // some code
}

$.ajax({
   url:method1(),
   success:function(){
   method2();
}
})
32
TuanTruong

Ou vous pouvez déclencher un événement personnalisé quand une fonction est terminée, puis le lier au document:

function a() {
    // first function code here
    $(document).trigger('function_a_complete');
}

function b() {
    // second function code here
}

$(document).bind('function_a_complete', b);

En utilisant cette méthode, la fonction 'b' ne peut exécuter la fonction APRES que 'a', car le déclencheur n'existe que lorsque l'exécution de la fonction a est terminée.

19
de Raad

Cela dépend de ce que fait la fonction1.

Si function1 exécute un script javascript synchrone simple, comme la mise à jour d'une valeur div ou quelque chose d'autre, function2 se déclenche une fois que function1 est terminé.

Si function1 effectue un appel asynchrone, tel qu'un appel AJAX, vous devrez créer une méthode "callback" (la plupart des API ajax ont un paramètre de fonction callback). Ensuite, appelez function2 dans le rappel. par exemple:

function1()
{
  new AjaxCall(ajaxOptions, MyCallback);
}

function MyCallback(result)
{
  function2(result);
}
2
Russell

tu peux le faire comme ça

$.when(funtion1()).then(function(){
    funtion2();
})
1
Jay Momaya

Si function1 est une fonction de synchronisation que vous souhaitez transformer en une fonction asynchrone, car elle prend un certain temps et vous n'avez aucun contrôle sur celle-ci pour ajouter un rappel:

function function1 (someVariable) {
    var date = Date.now ();
    while (Date.now () - date < 2000);      // function1 takes some time to complete
    console.log (someVariable);
}
function function2 (someVariable) {
    console.log (someVariable);
}
function onClick () {
    window.setTimeout (() => { function1 ("This is function1"); }, 0);
    window.setTimeout (() => { function2 ("This is function2"); }, 0);
    console.log ("Click handled");  // To show that the function will return before both functions are executed
}
onClick ();

La sortie sera:

Click handled

... et après 2 secondes:

This is function 1
This is function 2

Cela fonctionne parce que l'appel de window.setTimeout () ajoutera une tâche à la boucle de tâches JS runtine, ce qui est le cas d'un appel asynchrone, et parce que le principe de base de "l'exécution complète" de l'exécution de JS garantit que onClick () n'est jamais interrompu avant la fin.

Notez que c'est aussi drôle que le code soit difficile à comprendre ...

0
StashOfCode

J'ai eu un problème avec ça. Malgré l'utilisation du code ci-dessus, cela ne fonctionnait pas. Plus tard, avec l'aide d'autres personnes, j'ai réalisé que ma première fonction était asynchrone et que la deuxième fonction était synchrone. 

Ainsi, la version asynchrone était exécutée après la fonction synchrone malgré le code que j'ai écrit.

J'ai trouvé une solution de contournement dans mon cas en appelant la deuxième fonction à la fin de ma première fonction.

0
Rahul Makhija