Jeśli potrzebuję wywołać te funkcje jedna po drugiej,
$('#art1').animate({'width':'1000px'},1000);
$('#art2').animate({'width':'1000px'},1000);
$('#art3').animate({'width':'1000px'},1000);
Wiem, że w jQuery mógłbym zrobić coś takiego:
$('#art1').animate({'width':'1000px'},1000,'linear',function(){
$('#art2').animate({'width':'1000px'},1000,'linear',function(){
$('#art3').animate({'width':'1000px'},1000);
});
});
Ale załóżmy, że nie używam jQuery i chcę wywołać:
some_3secs_function(some_value);
some_5secs_function(some_value);
some_8secs_function(some_value);
Jak powinienem wywołać te funkcje, aby wykonać some_3secs_function
, a PO zakończeniu tego wywołania, wykonać some_5secs_function
i PO zakończeniu tego wywołania, a następnie wywołać some_8secs_function
?
AKTUALIZACJA:
To nadal nie działa:
(function(callback){
$('#art1').animate({'width':'1000px'},1000);
callback();
})((function(callback2){
$('#art2').animate({'width':'1000px'},1000);
callback2();
})(function(){
$('#art3').animate({'width':'1000px'},1000);
}));
Trzy animacje rozpoczynają się w tym samym czasie
Gdzie jest mój błąd?
Odpowiedzi:
W Javascript są funkcje synchroniczne i asynchroniczne .
Funkcje synchroniczne
Większość funkcji w Javascript jest synchroniczna. Gdybyś miał wywołać kilka funkcji synchronicznych z rzędu
wykonają w kolejności.
doSomethingElse
nie rozpocznie się, dopóki siędoSomething
nie zakończy.doSomethingUsefulThisTime
z kolei nie rozpocznie się, dopóki siędoSomethingElse
nie zakończy.Funkcje asynchroniczne
Jednak funkcje asynchroniczne nie będą na siebie czekać. Spójrzmy na ten sam przykład kodu, który mieliśmy powyżej, tym razem zakładając, że funkcje są asynchroniczne
Funkcje zostaną zainicjowane po kolei, ale wszystkie będą wykonywane mniej więcej w tym samym czasie. Nie możesz konsekwentnie przewidzieć, który z nich zakończy się pierwszy: ten, który zajmie najkrótszy czas, zakończy się jako pierwszy.
Ale czasami chcesz, aby funkcje, które są asynchroniczne, były wykonywane po kolei, a czasami chcesz, aby funkcje, które są synchroniczne, były wykonywane asynchronicznie. Na szczęście jest to możliwe odpowiednio w przypadku wywołań zwrotnych i limitów czasu.
Callback
Załóżmy, że mamy trzy funkcje asynchroniczne, które chcemy wykonać w kolejności
some_3secs_function
,some_5secs_function
isome_8secs_function
.Ponieważ funkcje mogą być przekazywane jako argumenty w JavaScript, możesz przekazać funkcję jako wywołanie zwrotne do wykonania po jej zakończeniu.
Jeśli stworzymy takie funkcje
wtedy możesz zadzwonić po kolei, na przykład:
Limity czasu
W JavaScript możesz nakazać funkcji, aby wykonywała się po określonym czasie (w milisekundach). W efekcie może to spowodować, że funkcje synchroniczne będą działać asynchronicznie.
Jeśli mamy trzy funkcje synchroniczne, możemy je wykonywać asynchronicznie za pomocą
setTimeout
funkcji.Jest to jednak trochę brzydkie i narusza zasadę DRY [wikipedia] . Moglibyśmy trochę to uporządkować, tworząc funkcję, która akceptuje tablicę funkcji i limit czasu.
Można to nazwać tak:
Podsumowując, jeśli masz funkcje asynchroniczne, które chcesz wykonywać synchronicznie, użyj wywołań zwrotnych, a jeśli masz funkcje synchroniczne, które chcesz wykonywać asynchronicznie, użyj limitów czasu.
źródło
Ta odpowiedź wykorzystuje standardową
promises
funkcję JavaScriptECMAScript 6
. Jeśli Twoja platforma docelowa nie obsługujepromises
, wypełnij ją PromiseJs .Spójrz na moją odpowiedź tutaj Poczekaj, aż funkcja z animacjami zostanie zakończona, aż do uruchomienia innej funkcji, jeśli chcesz użyć
jQuery
animacji.Oto, jak wyglądałby Twój kod z
ES6 Promises
ijQuery animations
.Można również zawijać zwykłe metody
Promises
.then
Metoda jest wykonywana, gdy tylkoPromise
skończył. Zwykle wartość zwracanafunction
przekazywana dothen
jest przekazywana do następnej jako wynik.Ale jeśli
Promise
zostanie zwrócone a, następnathen
funkcja czeka doPromise
zakończenia wykonywania i odbiera wyniki (wartość, do której jest przekazywanafulfill
).źródło
Wygląda na to, że nie w pełni doceniasz różnicę między wykonywaniem funkcji synchronicznych i asynchronicznych .
Kod podany w aktualizacji natychmiast wykonuje każdą z funkcji zwrotnych, co z kolei natychmiast uruchamia animację. Animacje są jednak wykonywane asynchronicznie . Działa to tak:
setTimeout
funkcję zawierającą następny krok animacji i opóźnieniesetTimeout
executeTrwa to do zakończenia ostatniego kroku animacji. W międzyczasie funkcje synchroniczne już dawno zostały zakończone. Innymi słowy, wywołanie
animate
funkcji nie zajmuje tak naprawdę 3 sekund. Efekt jest symulowany przez opóźnienia i wywołania zwrotne.Potrzebujesz kolejki . Wewnętrznie, jQuery kolejki animacji, tylko wykonując swoją oddzwanianie, gdy jej odpowiadających ukończy animacji. Jeśli wywołanie zwrotne rozpocznie kolejną animację, efekt jest taki, że są one wykonywane po kolei.
W najprostszym przypadku jest to równoważne z następującym:
Oto ogólna asynchroniczna funkcja pętli. Wywoła podane funkcje po kolei, czekając między nimi określoną liczbę sekund.
Stosowanie:
Możesz oczywiście zmodyfikować to, aby wykorzystać konfigurowalne czasy oczekiwania lub natychmiast wykonać pierwszą funkcję lub zatrzymać wykonywanie, gdy funkcja w łańcuchu powróci
false
lub doapply
funkcji w określonym kontekście lub cokolwiek innego, czego możesz potrzebować.źródło
Wierzę, że biblioteka asynchroniczna zapewni ci bardzo elegancki sposób na zrobienie tego. Chociaż obietnice i wywołania zwrotne mogą być nieco trudne do pogodzenia, asynchronizacja może zapewnić zgrabne wzorce usprawniające proces myślowy. Aby uruchamiać funkcje szeregowo, należałoby umieścić je w wodospadzie asynchronicznym . W żargonie asynchronicznym każda funkcja nazywa się a,
task
która pobiera argumenty icallback
; która jest następną funkcją w sekwencji. Podstawowa struktura wyglądałaby mniej więcej tak:Właśnie próbowałem pokrótce wyjaśnić tutaj strukturę. Przeczytaj przewodnik po wodospadzie, aby uzyskać więcej informacji, jest całkiem dobrze napisany.
źródło
Twoje funkcje powinny przyjmować funkcję zwrotną, która jest wywoływana po zakończeniu.
wówczas użycie byłoby takie:
źródło
Nie będę tutaj wdawać się w szczegółową dyskusję na temat setTimeout, ale:
źródło
Ponieważ oznaczyłeś go za pomocą javascript, użyłbym kontrolki timera, ponieważ nazwy twoich funkcji to 3, 5 i 8 sekund. Więc uruchom stoper, 3 sekundy w, zadzwoń do pierwszego, 5 sekund do drugiego, 8 sekund do trzeciego, a kiedy skończy, zatrzymaj stoper.
Zwykle w JavaScript to, co masz, jest poprawne, ponieważ funkcje działają jedna po drugiej, ale ponieważ wygląda na to, że próbujesz wykonać animację czasową, najlepszym rozwiązaniem będzie zegar.
źródło
źródło
next
?Możesz również wykorzystać obietnice w ten sposób:
Trzeba by zrobić
some_value
globalne, aby uzyskać do niego dostęp od wewnątrz .NastępnieAlternatywnie, z funkcji zewnętrznej możesz zwrócić wartość, której użyłaby funkcja wewnętrzna, na przykład:
źródło
Używam funkcji „waitUntil” opartej na setTimeout javascript
To działałoby idealnie, gdyby funkcje ustawiały pewien warunek na true, który byłby w stanie sondować. Dodatkowo jest wyposażony w limity czasu, które oferują alternatywy na wypadek, gdyby funkcja nie wykonała czegoś (nawet w przedziale czasowym. Pomyśl o opiniach użytkowników!)
na przykład
źródło
Jeśli metoda 1 ma zostać wykonana po metodzie 2, 3, 4. Poniższy fragment kodu może być rozwiązaniem tego problemu przy użyciu obiektu Deferred w JavaScript.
źródło