Como o JavaScript lida com respostas AJAX em segundo plano?

139

Como o JavaScript é executado em um único thread, depois que uma solicitação AJAX é feita, o que realmente acontece em segundo plano? Eu gostaria de ter uma visão mais profunda disso, alguém pode lançar alguma luz?

aziz punjani
fonte
6
Uma descrição muito boa está aqui: stackoverflow.com/questions/2914161/ajax-multi-threaded
Jonathan M
3
Código JavaScript é rosca única (exceto para os trabalhadores da web), mas não o navegador que está executando o motor JavaScript ...
Juan Mendes
@JuanMendes O JavaScript é executado em um segmento, enquanto a Fila de Eventos é executada em outro segmento?
Shaun Luttin
1
@ShaunLuttin Não, a fila de eventos é o que inicia o JavaScript
Juan Mendes

Respostas:

213

Abaixo das capas, o javascript tem uma fila de eventos. Sempre que um encadeamento de execução javascript termina, ele verifica se há outro evento na fila para processar. Se houver, ele sai da fila e aciona esse evento (como um clique do mouse, por exemplo).

A rede de código nativo que fica sob a chamada ajax saberá quando a resposta ajax for concluída e um evento será adicionado à fila de eventos javascript. Como o código nativo sabe quando a chamada ajax é feita depende da implementação. Pode ser implementado com threads ou também pode ser orientado por eventos (isso realmente não importa). O ponto da implementação é que, quando a resposta do ajax for concluída, algum código nativo saberá que foi feito e colocará um evento na fila JS.

Se nenhum Javascript estiver em execução no momento, o evento será acionado imediatamente, o que executará o manipulador de resposta ajax. Se algo estiver em execução no momento, o evento será processado quando o segmento de execução javascript atual terminar. Não é necessário realizar nenhuma pesquisa pelo mecanismo javascript. Quando uma parte do Javascript termina a execução, o mecanismo JS apenas verifica a fila de eventos para ver se há mais alguma coisa que precisa ser executada. Nesse caso, ele remove o próximo evento da fila e o executa (chamando uma ou mais funções de retorno de chamada registradas para esse evento). Se nada estiver na fila de eventos, o interpretador JS terá tempo livre (coleta de lixo ou inativo) até que um agente externo coloque outra coisa na fila de eventos e a ative novamente.

Como todos os eventos externos passam pela fila de eventos e nenhum evento é acionado enquanto o javascript está executando outra coisa, ele permanece com um único encadeamento.

Aqui estão alguns artigos sobre os detalhes:

jfriend00
fonte
Obrigado por isso. Suspeitei que fosse esse o caso, mas é bom saber com certeza. Eu tenho um loop for, no qual envio muitas solicitações de 'ajax'. No meu manipulador (para cada solicitação - retornada em ordem arbitrária), eu executo algum código que pode levar algum tempo. É bom saber que isso definitivamente deve funcionar.
iPadDeveloper2011
4
@telandor - os eventos são executados na ordem FIFO (é possível que haja algumas exceções de casos extremos, mas a intenção é FIFO). Alguns eventos são tratados de maneira ligeiramente diferente. Por exemplo, eventos de remoção de rato não se acumulam na fila (provavelmente porque eles poderiam facilmente transbordar). Quando o mouse se move e um evento mousemove já está na fila e não há outros eventos mais recentes na fila, ele é atualizado com a posição mais recente, em vez de um novo evento adicionado. Eu acho que provavelmente os eventos com timer de intervalo também são tratados especialmente para evitar que eles se acumulem na fila.
jfriend00
2
@elandeland - o que você precisa explicar mais? É FIFO. Adicionei mais alguns artigos de referência à minha resposta. As únicas execuções ao FIFO que eu conheço são eventos imediatamente acionados. Você chama .focus()um item e isso aciona alguns outros eventos, como um evento de "desfoque" no item com foco. Esse evento de desfoque ocorre de forma síncrona e não passa pela fila de eventos, portanto aconteceria imediatamente antes de outras coisas que possam estar na fila de eventos. Na prática, nunca achei que isso fosse uma preocupação prática.
jfriend00
2
@telandor - Não há várias filas por documento do navegador. Há uma fila e tudo sai em série FIFO in / out. Portanto, os tempos limite e as respostas ajax, os eventos do mouse e do teclado passam na mesma fila. O que foi colocado na fila primeiro é executado primeiro.
precisa saber é o seguinte
1
@CleanCrispCode - Thx. Eu o adicionei como uma referência útil à minha resposta.
usar o seguinte comando
16

Você pode encontrar aqui uma documentação muito completa sobre manipulação de eventos em javascript.
Foi escrito por um cara que trabalha na implementação de javascript no Navegador Opera.

Mais precisamente, observe os títulos: "Fluxo de Eventos", "Fila de Eventos" e "Eventos Não-Usuário": você aprenderá que:

  1. Javascript é executado em um único segmento para cada guia ou janela do navegador.
  2. Eventos são enfileirados e executados sequencialmente.
  3. XMLHttpRequest são executados pela implementação e retornos de chamada são executados usando a fila de eventos.

Nota: O link original era: link , mas agora está morto.

qwertzguy
fonte
1

Quero elaborar um pouco sobre a implementação do ajax mencionada nas respostas.

Embora a execução Javascript (regular) não seja multiencadeada - como observado nas respostas acima - no entanto , o tratamento real do AJAX responses(assim como o tratamento de solicitações) não é Javascript e, geralmente - é multiencadeado. (consulte implementação da fonte de cromo de XMLHttpRequest na que discutiremos acima)

e eu vou explicar, vamos pegar o seguinte código:

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(- após a etapa 1), enquanto o código js continua em execução (etapas 2 e depois), o navegador inicia o trabalho real de: 1. formatar uma solicitação tcp 2. abrir um soquete 3. enviar cabeçalhos 4. handshaking 5. enviar corpo 6. resposta em espera 7. cabeçalhos de leitura 8. corpo de leitura etc. toda essa implementação geralmente é executada em um encadeamento diferente, paralelamente à execução do código js. por exemplo, a implementação de cromo mencionada usa o Threadable Loader para digg-into 😉 (você também pode obter alguma impressão olhando a guia de rede de um carregamento de página, verá algumas solicitações simultâneas).

em conclusão, eu diria que - pelo menos - a maioria das operações de E / S pode ser feita simultaneamente / assíncrona (e você pode tirar proveito disso usando uma espera por exemplo). mas toda a interação com essas operações (a emissão, a execução do retorno de chamada js) é síncrona.

shmulik friedman
fonte