Jak JavaScript obsługuje odpowiedzi AJAX w tle?

139

Ponieważ JavaScript działa w jednym wątku, po wysłaniu żądania AJAX, co właściwie dzieje się w tle? Chciałbym uzyskać głębszy wgląd w to, czy ktoś może rzucić trochę światła?

aziz punjani
źródło
6
Całkiem dobry opis jest tutaj: stackoverflow.com/questions/2914161/ajax-multi-threaded
Jonathan M
3
Kod JavaScript jest jednowątkowy (z wyjątkiem pracowników WWW), ale nie przeglądarka, na której działa silnik JavaScript ...
Juan Mendes,
@JuanMendes Czy JavaScript działa w jednym wątku, podczas gdy kolejka zdarzeń działa w innym wątku?
Shaun Luttin
1
@ShaunLuttin Nie, kolejka zdarzeń uruchamia JavaScript
Juan Mendes

Odpowiedzi:

213

Pod okładkami javascript ma kolejkę zdarzeń. Za każdym razem, gdy kończy się wątek wykonywania javascript, sprawdza, czy w kolejce jest inne zdarzenie do przetworzenia. Jeśli tak, to wyciąga go z kolejki i wyzwala to zdarzenie (na przykład kliknięcie myszą).

Natywny kod sieciowy, który znajduje się pod wywołaniem Ajax, będzie wiedział, kiedy odpowiedź Ajax zostanie wykonana, a zdarzenie zostanie dodane do kolejki zdarzeń javascript. Skąd kod natywny wie, kiedy wywołanie AJAX jest wykonywane, zależy od implementacji. Może być zaimplementowany za pomocą wątków lub może być sterowany zdarzeniami (nie ma to większego znaczenia). Celem implementacji jest to, że gdy odpowiedź AJAX jest zakończona, jakiś natywny kod będzie wiedział, że to jest zrobione i umieści zdarzenie w kolejce JS.

Jeśli żaden JavaScript nie jest uruchomiony w danym momencie, zdarzenie zostanie natychmiast wyzwolone, co uruchomi moduł obsługi odpowiedzi Ajax. Jeśli coś jest uruchomione w tym czasie, zdarzenie zostanie przetworzone po zakończeniu bieżącego wątku wykonywania javascript. Nie ma potrzeby odpytywania przez silnik javascript. Po zakończeniu wykonywania fragmentu JavaScript silnik JS sprawdza kolejkę zdarzeń, aby sprawdzić, czy jest jeszcze coś, co należy uruchomić. Jeśli tak, zdejmuje następne zdarzenie z kolejki i wykonuje je (wywołując jedną lub więcej funkcji zwrotnych zarejestrowanych dla tego zdarzenia). Jeśli nic nie znajduje się w kolejce zdarzeń, interpreter JS ma wolny czas (czyszczenie pamięci lub bezczynność) do momentu, gdy jakiś zewnętrzny agent umieści coś innego w kolejce zdarzeń i ponownie ją obudzi.

Ponieważ wszystkie zdarzenia zewnętrzne przechodzą przez kolejkę zdarzeń i żadne zdarzenie nie jest nigdy wyzwalane, gdy javascript faktycznie uruchamia coś innego, pozostaje on jednowątkowy.

Oto kilka artykułów na temat szczegółów:

jfriend00
źródło
Dziękuję za to. Podejrzewałem, że tak było, ale dobrze wiedzieć na pewno. Mam pętlę for, w której wysyłam wiele żądań „ajax”. W moim programie obsługi (dla każdego żądania - zwracanego w dowolnej kolejności) uruchamiam kod, który może zająć trochę czasu. Dobrze wiedzieć, że to zdecydowanie powinno działać.
iPadDeveloper2011
4
@telandor - zdarzenia są uruchamiane w kolejności FIFO (możliwe, że są wyjątki od skrajnych przypadków, ale intencją jest FIFO). Niektóre zdarzenia są traktowane nieco inaczej. Na przykład zdarzenia mousemove nie gromadzą się w kolejce (prawdopodobnie dlatego, że mogą łatwo przepełnić kolejkę). Gdy mysz porusza się, a zdarzenie mousemove jest już w kolejce i nie ma innych nowszych wydarzeń w kolejce, jest aktualizowane o najnowszą pozycję, a nie dodawane nowe zdarzenie. Wydaje mi się, że zdarzenia z interwalometrem są prawdopodobnie również traktowane specjalnie, aby uniknąć gromadzenia się w kolejce.
jfriend00
2
@telandor - co potrzebujesz wyjaśnić dalej? To jest FIFO. Do mojej odpowiedzi dodałem jeszcze kilka artykułów referencyjnych. Jedyne wykonania do FIFO, o których wiem, to zdarzenia wyzwalane natychmiast. Wzywasz .focus()element, a to wywołuje kilka innych zdarzeń, takich jak zdarzenie „rozmycia” elementu, na którym jest fokus. To zdarzenie rozmycia odbywa się synchronicznie i nie przechodzi przez kolejkę zdarzeń, więc wydarzy się od razu przed innymi rzeczami, które mogą znajdować się w kolejce zdarzeń. W praktyce nigdy nie uważałem tego za praktyczny problem.
jfriend00
2
@telandor - Nie ma wielu kolejek na dokument przeglądarki. Jest jedna kolejka i wszystko idzie seryjnie do / z FIFO. Zatem limity czasu i odpowiedzi Ajax oraz zdarzenia myszy i klawiatury są umieszczane w tej samej kolejce. Ktokolwiek zostanie umieszczony w kolejce jako pierwszy, zostanie uruchomiony jako pierwszy.
jfriend00
1
@CleanCrispCode - Thx. Dodałem to jako przydatne odniesienie do mojej odpowiedzi.
jfriend00
16

Znajdziesz tutaj bardzo kompletną dokumentację dotyczącą obsługi zdarzeń w javascript.
Został napisany przez gościa pracującego nad implementacją javascript w przeglądarce Opera.

Dokładniej, spójrz na tytuły: „Przebieg zdarzeń”, „Kolejkowanie zdarzeń” i „Zdarzenia nie-użytkowników”: dowiesz się, że:

  1. JavaScript działa w jednym wątku dla każdej karty lub okna przeglądarki.
  2. Zdarzenia są umieszczane w kolejce i wykonywane sekwencyjnie.
  3. XMLHttpRequest są uruchamiane przez implementację, a wywołania zwrotne są uruchamiane przy użyciu kolejki zdarzeń.

Uwaga: oryginalny link to: link , ale teraz jest martwy.

qwertzguy
źródło
1

Chcę trochę rozwinąć, odnośnie implementacji Ajax wspomnianej w odpowiedziach.

Chociaż (zwykłe) wykonanie JavaScript nie jest wielowątkowe - jak zauważono w powyższych odpowiedziach - jednak rzeczywista obsługa AJAX responses(podobnie jak obsługa żądań) nie jest JavaScriptem i - zwykle - jest wielowątkowa. (zobacz implementację XMLHttpRequest dla źródła chromu, którą omówimy powyżej)

i wyjaśnię, weźmy następujący kod:

var xhr = new XMLHttpRequest();

var t = Date.now;
xhr.open( "GET", "https://swx.cdn.skype.com/shared/v/1.2.15/SkypeBootstrap.min.js?v="+t(), true );

xhr.onload = function( e ) {
		console.log(t() + ': step 3');
    
    alert(this.response.substr(0,20));
};
console.log(t() + ': step 1');
xhr.send();
console.log(t() + ': step 2');

after an AJAX request is made(- po kroku 1), a następnie w trakcie wykonywania kodu js (krok 2 i później) przeglądarka rozpoczyna rzeczywistą pracę polegającą na: 1. formatowaniu żądania tcp 2. otwieraniu gniazda 3. wysyłaniu nagłówków 4. uzgadnianiu 5. wysyłaniu body 6. odpowiedź oczekująca 7. odczyt nagłówków 8. odczyt treści itp. Cała ta implementacja jest zwykle uruchamiana w innym wątku równolegle do wykonywania kodu js. na przykład, wspomniana implementacja chromu używa Threadable Loader aby zagłębić się w 😉 (możesz również odnieść wrażenie, patrząc na kartę sieciową ładowania strony, zobaczysz kilka jednoczesnych żądań).

Podsumowując, powiedziałbym, że - przynajmniej - większość operacji we / wy może być wykonywana jednocześnie / asynchronicznie (i można to wykorzystać, na przykład, używając await ). ale wszystkie interakcje z tymi operacjami (wydawanie, wykonanie wywołania zwrotnego js) są synchroniczne.

shmulik Friedman
źródło