Mam dwie funkcje JS. Jeden dzwoni do drugiego. W ramach funkcji wywoływania chciałbym zadzwonić do drugiej, poczekać na zakończenie tej funkcji, a następnie kontynuować. Na przykład / pseudo kod:
function firstFunction(){
for(i=0;i<x;i++){
// do something
}
};
function secondFunction(){
firstFunction()
// now wait for firstFunction to finish...
// do something else
};
Wymyśliłem to rozwiązanie, ale nie wiem, czy jest to mądry sposób, aby to zrobić.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
Czy to jest legalne? Czy istnieje bardziej elegancki sposób, aby sobie z tym poradzić? Być może z jQuery?
firstFunction
dokładnie to powoduje, że jest asynchroniczny? Tak czy inaczej - sprawdź obietniceOdpowiedzi:
Jednym ze sposobów radzenia sobie z taką pracą asynchroniczną jest użycie funkcji zwrotnej, np .:
Zgodnie z sugestią @Janaka Pushpakumara, możesz teraz używać funkcji strzałek, aby osiągnąć to samo. Na przykład:
firstFunction(() => console.log('huzzah, I\'m done!'))
Aktualizacja: Odpowiedziałem na to jakiś czas temu i naprawdę chcę to zaktualizować. Chociaż wywołania zwrotne są absolutnie w porządku, z mojego doświadczenia wynika, że powodują trudniejszy do odczytania i utrzymania kod. Są jednak sytuacje, w których nadal ich używam, takie jak przekazywanie zdarzeń w toku i tym podobnych jako parametrów. Ta aktualizacja ma na celu podkreślenie alternatyw.
Również oryginalne pytanie nie specificallty wspomnieć asynchronicznie, więc w przypadku gdy ktoś jest zdezorientowany, jeśli funkcja jest synchroniczny, to będą blokować kiedy dzwonił. Na przykład:
Jeśli choć sugeruje się, że funkcja jest asynchroniczna, moim dzisiejszym podejściem do asynchronicznej pracy jest asynchronizacja / czekanie. Na przykład:
IMO, async / await sprawia, że kod jest znacznie bardziej czytelny niż bezpośrednie stosowanie obietnic (przez większość czasu). Jeśli potrzebujesz poradzić sobie z błędami przechwytywania, użyj go z try / catch. Przeczytaj o tym więcej tutaj: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function .
źródło
Użyj asynchronicznie / oczekuj:
następnie użyj funkcji czekaj w innej funkcji, aby poczekać na jej powrót:
źródło
$(function() { await firstFunction(); secondFunction(); });
,?await
można go używać tylko wewnątrzasync
metody. Jeśli więc wprowadzisz funkcję rodzicaasync
, możesz wywołać dowolną liczbę osóbasync methods
zawait
taką funkcją lub bez niej.await
setTimeout
Wygląda na to, że brakuje Ci tutaj ważnej kwestii: JavaScript jest jednowątkowym środowiskiem wykonawczym. Spójrzmy jeszcze raz na twój kod, zauważ, że dodałem
alert("Here")
:Nie musisz czekać
isPaused
. Gdy zobaczysz alert „Tutaj”,isPaused
będziefalse
już ifirstFunction
powróci. Wynika to z faktu, że nie można „ustąpić” z wnętrzafor
pętli (// do something
), pętla może nie zostać przerwana i najpierw trzeba będzie ją całkowicie ukończyć (więcej szczegółów: obsługa wątków JavaScript i warunki wyścigu ).To powiedziawszy, nadal możesz sprawić, że kod przepływa wewnątrz,
firstFunction
aby był asynchroniczny i użyć albo wywołania zwrotnego, albo obiecać powiadomienie dzwoniącego. Musiałbyś zrezygnować zfor
pętli i symulować ją za pomocąif
( JSFiddle ):Na marginesie, JavaScript 1.7 wprowadził
yield
słowo kluczowe w ramach generatorów . To pozwoli „dziurkować” asynchroniczne dziury w inaczej synchronicznym przepływie kodu JavaScript ( więcej szczegółów i przykład ). Jednak obsługa przeglądarki dla generatorów jest obecnie ograniczona do Firefoksa i Chrome, AFAIK.źródło
Eleganckim sposobem czekania na zakończenie jednej funkcji jest użycie Promises z funkcją asynchroniczną / oczekującą .
setTimeout
, aby zademonstrować sytuację, w której wykonanie instrukcji zajęłoby trochę czasu.await
należy wykonać pierwszą funkcję przed wykonaniem instrukcji.Przykład:
Uwaga:
Można po prostu bez wartości jak tak . W moim przykładzie z wartości , które można następnie wykorzystać w drugiej funkcji.
resolve
Promise
resolve()
resolved
Promise
y
źródło
Jedynym problemem związanym z obietnicami jest to, że IE ich nie obsługuje. Edge ma, ale jest mnóstwo IE 10 i 11: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (kompatybilność na dole)
JavaScript jest więc jednowątkowy. Jeśli nie wykonujesz połączenia asynchronicznego, będzie ono działało przewidywalnie. Główny wątek JavaScript wykona jedną funkcję całkowicie przed wykonaniem następnej, w kolejności, w jakiej występują w kodzie. Gwarantowanie kolejności funkcji synchronicznych jest banalne - każda funkcja wykona się całkowicie w kolejności, w której została wywołana.
Pomyśl o funkcji synchronicznej jako atomowej jednostce pracy . Główny wątek JavaScript wykona go w pełni, w kolejności, w jakiej instrukcje pojawiają się w kodzie.
Ale wrzuć wywołanie asynchroniczne, jak w następującej sytuacji:
To nie robi tego, co chcesz . Natychmiast wykonuje funkcję 1, funkcję 2 i funkcję 3. Ładowanie div miga i zniknęło, podczas gdy wywołanie ajax nie jest prawie ukończone, mimo że
makeAjaxCall()
zostało zwrócone. POWIKŁANIE polega na tym, żemakeAjaxCall()
podzielił on swoją pracę na części, które są stopniowo zwiększane o każdy obrót głównego wątku JavaScript - zachowuje się asychronicznie. Ale ten sam główny wątek, podczas jednego wirowania / przebiegu, wykonał synchroniczne części szybko i przewidywalnie.Sposób w jaki sobie z tym poradziłem : Jak powiedziałem, funkcją jest atomowa jednostka pracy. Połączyłem kod funkcji 1 i 2 - kod funkcji 1 umieściłem przed funkcją asynch. Pozbyłem się funkcji 1. Wszystko, włącznie z wywołaniem asynchronicznym, wykonuje się przewidywalnie, w kolejności.
NASTĘPNIE, gdy zakończy się asynchroniczne wywołanie, po kilku obrotach głównego wątku JavaScript, niech wywoła funkcję 3. To gwarantuje kolejność . Na przykład w przypadku ajax program obsługi zdarzeń onreadystatechange jest wywoływany wiele razy. Kiedy zgłosi, że jest zakończone, wywołaj ostatnią żądaną funkcję.
Zgadzam się, że jest bałagan. Lubię, żeby kod był symetryczny, lubię, żeby funkcje wykonywały jedną rzecz (lub blisko niego) i nie lubię, aby wywołanie ajax w jakikolwiek sposób odpowiadało za wyświetlanie (tworzenie zależności od wywołującego). ALE, z asynchronicznym wywołaniem wbudowanym w funkcję synchroniczną, konieczne są kompromisy w celu zagwarantowania kolejności wykonania. I muszę kodować dla IE 10, więc nie obiecuję.
Podsumowanie : W przypadku połączeń synchronicznych zagwarantowanie porządku jest banalne. Każda funkcja wykonuje się w pełni w kolejności, w jakiej została wywołana. W przypadku funkcji z wywołaniem asynchronicznym jedynym sposobem na zagwarantowanie kolejności jest monitorowanie, kiedy zakończy się wywołanie asynchroniczne, i wywoływanie trzeciej funkcji po wykryciu tego stanu.
Dyskusje na temat wątków JavaScript można znaleźć na stronie : https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23 i https://developer.mozilla.org/en-US/docs/Web/JavaScript/ EventLoop
Kolejne podobne, wysoko ocenione pytanie na ten temat: Jak wywołać 3 funkcje, aby wykonać je jedna po drugiej?
źródło
To wymyśliłem, ponieważ muszę uruchomić kilka operacji w łańcuchu.
źródło
Twoja główna zabawa zadzwoni jako pierwsza, a następnie po jej zakończeniu zadzwoni kolejna zabawa.
źródło