Byłem pod wrażeniem, że JavaScript zawsze był asynchroniczny. Dowiedziałem się jednak, że istnieją sytuacje, w których tak nie jest (tj. Manipulacje DOM). Czy jest gdzieś dobre odniesienie, kiedy będzie synchroniczne i kiedy będzie asynchroniczne? Czy jQuery w ogóle na to wpływa?
javascript
jquery
Brian
źródło
źródło
Odpowiedzi:
JavaScript jest zawsze synchroniczny i jednowątkowy. Jeśli wykonujesz blok kodu JavaScript na stronie, żadne inne JavaScript na tej stronie nie będzie aktualnie wykonywane.
JavaScript jest tylko asynchroniczny w tym sensie, że może wykonywać na przykład wywołania Ajax. Wywołanie Ajax przestanie być wykonywane, a inny kod będzie mógł zostać wykonany, dopóki połączenie nie powróci (pomyślnie lub w inny sposób), w którym to momencie wywołanie zwrotne będzie działać synchronicznie. W tym momencie nie będzie działał żaden inny kod. Nie zakłóci to żadnego innego uruchomionego kodu.
Zegary JavaScript działają z tym samym rodzajem wywołania zwrotnego.
Opisywanie JavaScript jako asynchronicznego może być mylące. Dokładniej jest powiedzieć, że JavaScript jest synchroniczny i jednowątkowy z różnymi mechanizmami zwrotnymi.
jQuery ma opcję wywołań Ajax, aby były synchroniczne (z
async: false
opcją). Początkujący mogą mieć pokusę, aby używać tego niepoprawnie, ponieważ pozwala to na bardziej tradycyjny model programowania, do którego można być bardziej przyzwyczajonym. Problemem jest to, że ta opcja blokuje cały JavaScript na stronie, aż do końca, w tym wszystkie programy obsługi zdarzeń i timery.źródło
JavaScript jest jednowątkowy i ma synchroniczny model wykonania. Jednowątkowy oznacza, że jedno polecenie jest wykonywane jednocześnie. Synchroniczny oznacza jeden po drugim, tzn. Jeden wiersz kodu jest wykonywany jednocześnie w celu wyświetlenia kodu. Tak więc w JavaScript jedna rzecz dzieje się na raz.
Kontekst wykonania
Silnik JavaScript współdziała z innymi silnikami w przeglądarce. Na stosie wykonawczym JavaScript jest u dołu kontekst globalny, a następnie, gdy wywołujemy funkcje, silnik JavaScript tworzy nowe konteksty wykonania dla odpowiednich funkcji. Gdy wywoływana funkcja kończy działanie, kontekst wykonywania jest wyskakujący ze stosu, a następnie kontekst kontekstu wykonania jest wyskakujący itd. ...
Na przykład
W powyższym kodzie zostanie utworzony globalny kontekst wykonania, w tym kontekście
var one
będzie przechowywany, a jego wartość będzie wynosić 1 ... po wywołaniu wywołania xyz () zostanie utworzony nowy kontekst wykonania i jeśli zdefiniowalibyśmy jakąkolwiek zmienną w funkcji xyz zmienne te byłyby przechowywane w kontekście wykonania xyz (). W funkcji xyz wywołujemy abc (), a następnie tworzony jest kontekst wykonania abc () i umieszczany na stosie wykonania ... Teraz, kiedy abc () skończy, jego kontekst jest wyskakujący ze stosu, a następnie kontekst xyz () jest wyskakujący z stos, a następnie kontekst globalny zostanie wyświetlony ...Teraz o asynchronicznych wywołaniach zwrotnych; asynchroniczny oznacza więcej niż jeden na raz.
Podobnie jak stos wykonawczy, istnieje kolejka zdarzeń . Gdy chcemy otrzymywać powiadomienia o zdarzeniu w silniku JavaScript, możemy odsłuchać to zdarzenie, a to zdarzenie jest umieszczane w kolejce. Na przykład zdarzenie żądania Ajax lub zdarzenie żądania HTTP.
Ilekroć stos wykonawczy jest pusty, jak pokazano w powyższym przykładzie kodu, silnik JavaScript okresowo sprawdza kolejkę zdarzeń i sprawdza, czy istnieje jakieś zdarzenie, o którym należy powiadomić. Na przykład w kolejce były dwa zdarzenia: żądanie ajax i żądanie HTTP. Sprawdza również, czy istnieje funkcja, która musi zostać uruchomiona na wyzwalaczu zdarzenia ... Tak więc silnik JavaScript jest powiadamiany o zdarzeniu i zna odpowiednią funkcję do wykonania na tym zdarzeniu ... Tak więc silnik JavaScript wywołuje metodę funkcja obsługi, w przykładowym przypadku np. AjaxHandler () zostanie wywołana i jak zawsze, gdy wywoływana jest funkcja, jej kontekst wykonania jest umieszczony w kontekście wykonania, a teraz kończy się wykonywanie funkcji, a żądanie ajax zdarzenia jest również usuwane z kolejki zdarzeń ... Po zakończeniu AjaxHandler () stos wykonawczy jest pusty, więc silnik ponownie patrzy na kolejkę zdarzeń i uruchamia funkcję obsługi zdarzeń dla żądania HTTP, które było następne w kolejce. Należy pamiętać, że kolejka zdarzeń jest przetwarzana tylko wtedy, gdy stos wykonania jest pusty.
Na przykład zobacz poniższy kod wyjaśniający obsługę stosu i obsługę kolejek zdarzeń przez silnik Javascript.
I
Teraz uruchom stronę internetową i kliknij stronę i zobacz dane wyjściowe na konsoli. Wyjście będzie
Mechanizm JavaScript uruchamia kod synchronicznie, jak wyjaśniono w części dotyczącej kontekstu wykonania, przeglądarka asynchronicznie umieszcza elementy w kolejce zdarzeń. Tak więc funkcje, których wykonanie zajmuje bardzo dużo czasu, mogą zakłócać obsługę zdarzeń. Rzeczy, które dzieją się w przeglądarce, takie jak zdarzenia, są obsługiwane w ten sposób przez JavaScript, jeśli ma być uruchomiony detektor, silnik uruchomi go, gdy stos wykonawczy będzie pusty. Zdarzenia są przetwarzane w kolejności ich wystąpienia, więc część asynchroniczna dotyczy tego, co dzieje się poza silnikiem, tj. Co silnik powinien zrobić, gdy zdarzają się te zdarzenia zewnętrzne.
JavaScript jest więc zawsze synchroniczny.
źródło
JavaScript jest jednowątkowy i cały czas pracujesz nad normalnym synchronicznym wykonywaniem przepływu kodu.
Dobrym przykładem asynchronicznego zachowania, jakie może mieć JavaScript, są zdarzenia (interakcja użytkownika, wyniki żądania Ajax itp.) I liczniki czasu, w zasadzie działania, które mogą wystąpić w dowolnym momencie.
Poleciłbym rzucić okiem na następujący artykuł:
Ten artykuł pomoże Ci zrozumieć jednowątkowy charakter JavaScript i jak wewnętrznie działają liczniki oraz jak działa asynchroniczne wykonywanie JavaScript.
źródło
Dla kogoś, kto naprawdę rozumie, jak działa JS, to pytanie może się wydawać złe, jednak większość ludzi, którzy używają JS, nie ma tak głębokiego wglądu (i niekoniecznie potrzebuje go), a dla nich jest to dość mylące, spróbuj odpowiedzieć z tej perspektywy.
JS jest synchroniczny w sposobie wykonywania kodu. każda linia biegnie tylko za linią przed jej zakończeniem i jeśli linia ta wywołuje funkcję po zakończeniu ect ...
Główny punkt zamieszania wynika z faktu, że Twoja przeglądarka jest w stanie powiedzieć JS, aby wyciął więcej kodu w dowolnym momencie (na przykład, jak można wyciąć więcej kodu JS na stronie z konsoli). Jako przykład, JS ma funkcje oddzwaniania, których celem jest umożliwienie JS BEHAVE asynchronicznie, aby dalsze części JS mogły działać, czekając na wykonanie funkcji JS (
GET
wywołanie IE ) w celu odpowiedzi, JS będzie działać do przeglądarka ma odpowiedź w tym momencie pętla zdarzeń (przeglądarka) wykona kod JS, który wywołuje funkcję wywołania zwrotnego.Ponieważ pętla zdarzeń (przeglądarka) może wprowadzić więcej JS do wykonania w dowolnym momencie, w tym sensie JS jest asynchroniczny (podstawowe rzeczy, które spowodują, że przeglądarka wprowadzi kod JS, to limity czasu, wywołania zwrotne i zdarzenia)
Mam nadzieję, że jest to wystarczająco jasne, aby komuś pomóc.
źródło
Definicja
Określenia „asynchroniczny” można używać w nieco innych znaczeniach, co powoduje pozornie sprzeczne odpowiedzi, podczas gdy w rzeczywistości tak nie jest. Wikipedia na temat asynchronii ma następującą definicję:
kod inny niż JavaScript może ustawiać w kolejce takie zdarzenia „zewnętrzne” do niektórych kolejek zdarzeń JavaScript. Ale to jest tak daleko, jak to możliwe.
Bez uprzedzenia
Nie ma zewnętrznej przerwy w uruchamianiu kodu JavaScript w celu wykonania innego kodu JavaScript w skrypcie. Fragmenty JavaScript są wykonywane jeden po drugim, a kolejność jest ustalana na podstawie kolejności zdarzeń w każdej kolejce zdarzeń oraz priorytetu tych kolejek.
Na przykład możesz być absolutnie pewien, że żaden inny kod JavaScript (w tym samym skrypcie) nigdy się nie uruchomi podczas wykonywania następującego fragmentu kodu:
Innymi słowy, JavaScript nie ma żadnego pierwszeństwa . Cokolwiek może być w kolejkach zdarzeń, przetwarzanie tych zdarzeń będzie musiało poczekać, aż taki fragment kodu dobiegnie końca. Specyfikacja EcmaScript mówi w sekcji 8.4 Zadania i kolejki zadań :
Przykłady asynchronii
Jak już napisali inni, istnieje kilka sytuacji, w których asynchronia wchodzi w grę w JavaScript i zawsze wiąże się z kolejką zdarzeń, co może spowodować wykonanie JavaScript, gdy nie jest wykonywany żaden inny kod JavaScript:
setTimeout()
: agent (np. przeglądarka) umieści zdarzenie w kolejce zdarzeń po upływie limitu czasu. Monitorowanie czasu i umieszczanie zdarzenia w kolejce odbywa się za pomocą kodu innego niż JavaScript, więc można sobie wyobrazić, że dzieje się to równolegle z potencjalnym wykonaniem jakiegoś kodu JavaScript. Ale podane wywołanie zwrotnesetTimeout
może zostać wykonane tylko wtedy, gdy aktualnie wykonywany kod JavaScript dobiegnie końca i odczytywana jest odpowiednia kolejka zdarzeń.fetch()
: agent użyje funkcji systemu operacyjnego do wykonania żądania HTTP i monitorowania każdej przychodzącej odpowiedzi. Ponownie to zadanie inne niż JavaScript może działać równolegle z niektórymi kodami JavaScript, które są nadal wykonywane. Ale procedura rozstrzygania obietnicy, która rozwiąże obietnicę zwróconą przezfetch()
, może zostać wykonana tylko wtedy, gdy aktualnie wykonywany skrypt JavaScript dobiegnie końca.requestAnimationFrame()
: silnik renderujący przeglądarki (inny niż JavaScript) umieści zdarzenie w kolejce JavaScript, gdy będzie gotowy do wykonania operacji malowania. Podczas przetwarzania zdarzenia JavaScript wykonywana jest funkcja zwrotna.queueMicrotask()
: natychmiast umieszcza zdarzenie w kolejce do wykonywania wielu zadań. Oddzwanianie zostanie wykonane, gdy stos wywołań będzie pusty, a zdarzenie zostanie zużyte.Istnieje wiele innych przykładów, ale wszystkie te funkcje są dostarczane przez środowisko hosta, a nie przez rdzeń EcmaScript. Dzięki rdzeniu EcmaScript możesz synchronicznie umieszczać zdarzenie w kolejce Promise Job
Promise.resolve()
.Konstrukcje językowe
ECMAScript oferuje kilka konstrukcji językowych w celu wspierania wzór asynchrony, takie jak
yield
,async
,await
. Ale niech się nie pomyli: żaden kod JavaScript nie zostanie przerwany przez zdarzenie zewnętrzne. W „przerwa”, któreyield
iawait
wydają się zapewniać tylko kontrolowane, predefiniowane sposób powrocie z wywołania funkcji i przywracając jej kontekst wykonywania później, albo za pomocą kodu JS (w przypadkuyield
), albo kolejki zdarzeń (w przypadkuawait
).Obsługa zdarzeń DOM
Gdy kod JavaScript uzyskuje dostęp do interfejsu API DOM, może to w niektórych przypadkach spowodować, że interfejs API DOM wyzwoli jedno lub więcej powiadomień synchronicznych. A jeśli twój kod nasłuchuje zdarzenia, zostanie wywołany.
Może się to wydawać wyprzedzającą współbieżnością, ale tak nie jest: po zwróceniu procedur obsługi zdarzeń DOM API w końcu również zwróci i oryginalny kod JavaScript będzie kontynuowany.
W innych przypadkach DOM API po prostu wywoła zdarzenie w odpowiedniej kolejce zdarzeń, a JavaScript wykryje je po opróżnieniu stosu wywołań.
Zobacz zdarzenia synchroniczne i asynchroniczne
źródło
Jest synchroniczny we wszystkich przypadkach.
Przykład blokowania wątku za pomocą
Promises
:Dane wyjściowe będą:
źródło