Eu estou pensando sobre isso e é isso que eu vim com:
Digamos que temos um código como este:
console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);
Uma solicitação é recebida e o mecanismo JS começa a executar o código acima, passo a passo. As duas primeiras são de sincronização. Mas quando se trata de setTimeout
método, ele se torna uma execução assíncrona. Mas o JS retorna imediatamente e continua executando, que é chamado Non-Blocking
ou Async
. E continua trabalhando em outros etc.
Os resultados dessa execução são os seguintes:
acdb
Então, basicamente, o segundo setTimeout
foi concluído primeiro e sua função de retorno de chamada é executada antes do primeiro, e isso faz sentido.
Estamos falando de aplicativos single-threaded aqui. O JS Engine continua executando isso e, a menos que termine a primeira solicitação, ela não passará para a segunda. Mas o bom é que não esperará que as operações de bloqueio setTimeout
sejam resolvidas, para que seja mais rápido porque aceita as novas solicitações recebidas.
Mas minhas perguntas surgem em torno dos seguintes itens:
# 1: Se estamos falando de um aplicativo de thread único, qual mecanismo processa setTimeouts
enquanto o mecanismo JS aceita mais solicitações e as executa? Como o thread único continua trabalhando em outras solicitações? O que funciona setTimeout
enquanto outras solicitações continuam chegando e são executadas.
# 2: Se essas setTimeout
funções são executadas nos bastidores enquanto mais solicitações são recebidas e executadas, o que executa as execuções assíncronas nos bastidores? Sobre o que falamos sobre o que é chamado de EventLoop
?
# 3: Mas o método inteiro não deve ser colocado no EventLoop
modo para que tudo seja executado e o método de retorno de chamada seja chamado? Isto é o que eu entendo quando falo sobre funções de retorno de chamada:
function downloadFile(filePath, callback)
{
blah.downloadFile(filePath);
callback();
}
Mas, neste caso, como o JS Engine sabe se é uma função assíncrona para poder colocar o retorno de chamada na EventLoop? Perhaps something like the
palavra-chave async` em C # ou algum tipo de atributo que indica que o método que o JS Engine adotará é um método assíncrono e deve ser tratado em conformidade.
# 4: Mas um artigo diz muito contrário ao que eu estava imaginando sobre como as coisas podem estar funcionando:
O loop de eventos é uma fila de funções de retorno de chamada. Quando uma função assíncrona é executada, a função de retorno de chamada é enviada para a fila. O mecanismo JavaScript não inicia o processamento do loop de eventos até que o código após a execução de uma função assíncrona.
# 5: E existe esta imagem aqui que pode ser útil, mas a primeira explicação na imagem está dizendo exatamente a mesma coisa mencionada na pergunta número 4:
Então, minha pergunta aqui é obter alguns esclarecimentos sobre os itens listados acima?
Respostas:
Há apenas um encadeamento no processo do nó que realmente executará o JavaScript do seu programa. No entanto, no próprio nó, na verdade, existem vários threads manipulando a operação do mecanismo de loop de eventos, e isso inclui um conjunto de threads de E / S e vários outros. A chave é que o número desses encadeamentos não corresponde ao número de conexões simultâneas sendo manipuladas como faria em um modelo de simultaneidade de encadeamento por conexão.
Agora, sobre "executar setTimeouts", quando você invoca
setTimeout
, tudo o que faz é basicamente atualizar uma estrutura de dados de funções a serem executadas em um momento no futuro. Basicamente, ele tem várias filas de coisas que precisam ser executadas e cada "marca" do loop de eventos seleciona uma, remove-a da fila e a executa.Uma coisa importante a entender é que o nó depende do sistema operacional durante a maior parte do trabalho pesado. Portanto, as solicitações de rede recebidas são realmente rastreadas pelo próprio sistema operacional e, quando o nó está pronto para lidar com uma, apenas usa uma chamada do sistema para solicitar ao sistema operacional uma solicitação de rede com dados prontos para serem processados. Grande parte do nó "trabalho" de E / S faz é "Ei, SO, conseguiu uma conexão de rede com os dados prontos para leitura?" ou "Ei, SO, alguma das minhas chamadas pendentes do sistema de arquivos tem dados prontos?". Com base no seu algoritmo interno e no design do mecanismo de loop de eventos, o nó selecionará um "tick" de JavaScript para executar, executá-lo e, em seguida, repita o processo novamente. É isso que significa o loop de eventos. O nó está basicamente determinando o tempo todo "qual é o próximo pedacinho de JavaScript que devo executar?" E depois executá-lo.
setTimeout
ouprocess.nextTick
.Nenhum JavaScript é executado nos bastidores. Todo o JavaScript em seu programa é executado na frente e no centro, um de cada vez. O que acontece nos bastidores é que o SO lida com as E / S e o nó aguarda que esteja pronto e o nó gerencia sua fila de javascript aguardando a execução.
Há um conjunto fixo de funções no núcleo do nó que são assíncronas porque fazem chamadas ao sistema e o nó sabe quais são porque precisam chamar o SO ou C ++. Basicamente, todas as E / S da rede e do sistema de arquivos, bem como as interações do processo filho, serão assíncronas e a única maneira que o JavaScript pode fazer com que o nó execute algo de forma assíncrona é invocando uma das funções assíncronas fornecidas pela biblioteca principal do nó. Mesmo se você estiver usando um pacote npm que define sua própria API, para gerar o loop de eventos, eventualmente o código do pacote npm chamará uma das funções assíncronas do núcleo do nó e é quando o nó sabe que o tick está completo e pode iniciar o evento algoritmo de loop novamente.
Sim, isso é verdade, mas é enganador. A principal coisa é o padrão normal é:
Então, sim, você pode bloquear totalmente o loop de eventos contando os números de Fibonacci de forma síncrona, todos na memória, todos no mesmo tick, e sim, isso congelaria totalmente seu programa. É simultaneidade cooperativa. Cada marca de JavaScript deve gerar o loop de eventos dentro de um período de tempo razoável ou a arquitetura geral falha.
fonte
process.nextTick
vssetTimeout
vssetImmediate
é sutilmente diferente, embora você realmente não deva se preocupar. Eu tenho uma postagem no blog chamada setTimeout e amigos que entra em mais detalhes.Existe um fantástico tutorial em vídeo de Philip Roberts, que explica o loop de eventos javascript da maneira mais simplista e conceitual. Todo desenvolvedor de javascript deve dar uma olhada.
Aqui está o link do vídeo no Youtube.
fonte
Não pense que o processo host seja de thread único, eles não são. O que é thread único é a parte do processo host que executa seu código javascript.
Exceto trabalhadores em segundo plano , mas estes complicam o cenário ...
Portanto, todo o seu código js é executado no mesmo encadeamento, e não há possibilidade de que duas partes diferentes do seu código js sejam executadas simultaneamente (portanto, você não precisa gerenciar o nigthmare de concorrência).
O código js que está executando é o último código que o processo do host captou do loop de eventos. No seu código, você pode basicamente fazer duas coisas: executar instruções síncronas e agendar funções a serem executadas no futuro, quando alguns eventos acontecerem.
Aqui está minha representação mental (cuidado: é só isso, não conheço os detalhes de implementação do navegador!) Do seu código de exemplo:
Enquanto seu código está em execução, outro encadeamento no processo host monitora todos os eventos do sistema que estão ocorrendo (cliques na interface do usuário, arquivos lidos, pacotes de redes recebidos etc.)
Quando seu código é concluído, ele é removido do loop de eventos e o processo do host retorna para verificá-lo, para verificar se há mais código para executar. O loop de eventos contém mais dois manipuladores de eventos: um a ser executado agora (a função justNow) e outro em um segundo (a função inAWhile).
O processo host agora tenta corresponder a todos os eventos para ver se existem manipuladores registrados para eles. Ele descobriu que o evento que justNow está esperando aconteceu, então ele começou a executar seu código. Quando a função justNow sai, ele verifica o loop de eventos outra vez, procurando por manipuladores de eventos. Supondo que 1 s tenha passado, ele executa a função inAWhile e assim por diante ....
fonte