Warten Sie, bis eine Funktion mit Animationen beendet ist, bis Sie eine andere Funktion ausführen


70

Ich habe ein Problem mit normalen ( Nicht-Ajax- ) Funktionen, die viele Animationen in jeder von ihnen beinhalten. Momentan habe ich einfach eine setTimeoutZwischenfunktion, aber diese ist nicht perfekt, da keine Browser / Computer gleich sind.

Zusätzlicher Hinweis: Beide haben separate Animationen / etc, die kollidieren.

Ich kann nicht einfach einen in die Rückruffunktion eines anderen setzen

// 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); 

Gibt es sowieso in js / jQuery:

// Pseudo-code
-do FunctionOne()
-when finished :: run -> FunctionTwo()

Ich weiß über $.when()& Bescheid $.done(), aber diese sind für AJAX ...


  • MEINE AKTUALISIERTE LÖSUNG

jQuery verfügt über eine exponierte Variable (die aus irgendeinem Grund nirgendwo in den jQuery-Dokumenten aufgeführt ist) mit dem Namen $ .timers, die das Array der derzeit stattfindenden Animationen enthält.

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);
};

Grundlegende Verwendung:

// 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();

});

2
Wenn FunctionOnees keine Auszeit gibt oder so, können Sie einfach anrufen FunctionOne(); FunctionTwo();, nicht wahr?
Waleed Khan

Das Problem ist, dass beide separate Animationen / usw. in unterschiedlichen Dateien usw. haben. Sie kollidieren also ...
Mark Pieszak - Trilon.io

3
$.whenund $.donesind nicht unbedingt nur für Ajax. Wenn Sie verschiedene asynchrone Aufgaben in FunctionOne haben, die Sie beenden möchten, bevor Sie FunctionTwo starten, können Sie DeferredObjekte erstellen , sie in ein Array resolve()$.when.apply($, array).then(function(){...});
einfügen

1
Globale sind böse, aber in diesem Fall könnte es sich lohnen, nur eine isRunningFlagge hinzuzufügen .
Ajax333221

1
Du hast meine App gespeichert, ich bin
unendlich

Antworten:


109

Sie können jQuery's verwenden $.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);

Sie können auch mehrere Verzögerungen zusammenpacken:

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();
    });
  });
};

http://jsfiddle.net/p22dK/


Wie er sagte, er verwendet Animationen, möchten Sie vielleicht .promise()
jQuerys

@Bergi Sie meinen, dass jQuery ein zurückgestelltes Objekt von zurückgibt animate? Denn sonst sehe ich hier nicht wirklich die Notwendigkeit des Versprechensobjekts.
Yoshi

Ja, ich meinte nicht die Deferred.promise, sondern die jQuery-Methode api.jquery.com/promise
Bergi

Oh wow, ich lese das alles jetzt Yoshi, gutes Zeug! Ich werde es morgen versuchen und versuchen, auch mit .promise herumzuspielen. Bin dankbar!
Mark Pieszak - Trilon.io

1
Entschuldigung für die Verspätung! Ich hatte endlich die Gelegenheit, mehr über aufgeschoben / erledigt / versprochen / wann usw. zu lesen. Und diese sind PERFEKT! Sie warten buchstäblich, bis alle Animationen für eine bestimmte Sache fertig sind. when ($ ('was auch immer')). done () funktioniert perfekt!
Mark Pieszak - Trilon.io

13

Fügen Sie am Ende der ersten Funktion Folgendes hinzu

return $.Deferred().resolve();

Rufen Sie beide Funktionen so auf

functionOne().done(functionTwo);

3

Zusammen mit Yoshis Antwort habe ich eine weitere sehr einfache Lösung (Rückruftyp) für Animationen gefunden.

jQuery verfügt über eine exponierte Variable (die aus irgendeinem Grund nirgendwo in den jQuery-Dokumenten aufgeführt ist) mit dem Namen $ .timers , die das Array der derzeit stattfindenden Animationen enthält.

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);
};

Grundlegende Verwendung:

functionOne(); // one with animations

animationsTest(functionTwo);

Hoffe das hilft einigen Leuten!


1

Ist es das, was du meinst, Mann: http://jsfiddle.net/LF75a/

Sie haben eine Funktion, die die nächste Funktion auslöst und so weiter, dh fügen Sie einen weiteren Funktionsaufruf hinzu und fügen Sie dann Ihren functionONeam unteren Rand hinzu.

Bitte lassen Sie mich wissen, wenn ich etwas verpasst habe, hoffe es passt zur Sache :)

oder dies: Rufen Sie eine Funktion auf, nachdem die vorherige Funktion abgeschlossen wurde

Code:

function hulk()
{
  // do some stuff...
}
function simpsons()
{
  // do some stuff...
  hulk();
}
function thor()
{
  // do some stuff...
  simpsons();
}

5
Rückruf ist die entsprechende JS-Antwort, IMO.
MalSu

Ich habe nur einen Funktionsaufruf. Ich kann die Funktion nicht ändern, muss aber meine andere Funktion nach dem ersten Abschluss ausführen.
Qwerty

Ich glaube, dass dies mit Animation nicht funktionieren würde, da es in der Regel zu Verzögerungen bei der Arbeit kommt
Muhammad Nour,

1

Diese Antwort verwendet promiseseine JavaScript-Funktion des ECMAScript 6Standards. Wenn Ihre Zielplattform dies nicht unterstützt promises, füllen Sie sie mit PromiseJs .

Sie können das DeferredObjekt, das jQuery für die Animation erstellt, mithilfe .promise()des Animationsaufrufs abrufen. Das Einwickeln dieser Deferredsin ES6Promises führt zu einem viel saubereren Code als die Verwendung von Timern.

Sie können auch Deferredsdirekt verwenden, dies wird jedoch generell nicht empfohlen, da sie nicht der Promises / A + -Spezifikation entsprechen.

Der resultierende Code würde folgendermaßen aussehen:

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();
});

Beachten Sie, dass die Funktion in Promise.all()das Versprechen zurückgibt. Hier geschieht Magie. Wenn in einem thenAnruf ein Versprechen zurückgegeben thenwird, wartet der nächste Anruf darauf, dass dieses Versprechen gelöst wird, bevor er ausgeführt wird.

jQuery verwendet für jedes Element eine Animationswarteschlange. Animationen auf demselben Element werden also synchron ausgeführt. In diesem Fall müssten Sie überhaupt keine Versprechen verwenden!

Ich habe die jQuery-Animationswarteschlange deaktiviert, um zu demonstrieren, wie es mit Versprechungen funktionieren würde.

Promise.all() nimmt eine Reihe von Versprechungen und schafft eine neue Promise , die beendet wird, nachdem alle Versprechungen in der Reihe beendet wurden.

Promise.race()nimmt auch eine Reihe von Versprechungen, endet aber, sobald die erste Promisefertig ist.


1

ECMAScript 6 UPDATE

Dies verwendet eine neue JavaScript-Funktion namens Promises

functionOne (). then (functionTwo);


0

Sie können dies über die Rückruffunktion tun.

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

Funktion function1 (param, callback) {... do stuff callback (); }}


0

Hier ist eine Lösung für n-Aufrufe (rekursive Funktion). 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);

0

Sie können das Javascript verwenden Promiseund async/awaiteinen synchronisierten Aufruf der Funktionen implementieren.

Angenommen, Sie möchten eine nReihe von Funktionen synchron ausführen , die in einem Array gespeichert sind. Hier ist meine Lösung dafür.

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);

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.