JavaScript é a espinha dorsal da web, potencializando funcionalidades dinâmicas do lado do cliente para bilhões de sites e aplicativos. Mas você já se perguntou como o JavaScript faz sua mágica em segundo plano? Nesta postagem, vamos nos aprofundar no funcionamento interno da natureza de thread único do JavaScript e explorar o conceito de programação assíncrona.
Quando dizemos que JavaScript é "single-threaded", significa que ele possui uma única pilha de chamadas. A pilha de chamadas é essencialmente a estrutura onde o JavaScript controla as funções que estão sendo executadas. Ele segue uma ordem Last In, First Out (LIFO), o que significa que a última função colocada na pilha será a primeira a terminar. Aqui está um exemplo de como isso funciona:
function first() { console.log('First function'); } function second() { console.log('Second function'); } first(); second();
Neste exemplo, a função first() é adicionada à pilha e executada. Depois de concluído, ele é retirado e a função second() é colocada na pilha e executada em seguida.
Embora as linguagens de thread único possam parecer limitadas porque só podem fazer uma coisa por vez, o uso inteligente de mecanismos assíncronos do JavaScript permite simular multitarefa.
JavaScript usa execução assíncrona para lidar com operações que podem levar muito tempo para serem concluídas, como solicitações de rede, E/S de arquivos ou temporizadores. Apesar de ser de thread único, ele pode gerenciar várias tarefas simultaneamente graças ao loop de eventos e à fila de retorno de chamada.
O loop de eventos é um conceito central no modelo de simultaneidade do JavaScript. Sua principal responsabilidade é gerenciar como o JavaScript lida com a execução assíncrona de código. Veja como funciona:
O código síncrono é executado primeiro. Quando o JavaScript é iniciado, ele executa todo o código do escopo global de maneira síncrona, linha por linha, usando a pilha de chamadas.
As tarefas assíncronas são enviadas para as APIs da Web (como setTimeout, fetch, etc.) ou APIs Node.js, onde serão processadas em segundo plano.
A fila de retorno de chamada é onde as operações assíncronas são colocadas depois de concluídas.
O loop de eventos verifica continuamente se a pilha de chamadas está vazia. Se a pilha estiver vazia, ele pega o primeiro item da fila de retorno de chamada e o coloca na pilha de chamadas, permitindo que seja executado.
A mágica do JavaScript assíncrono está nessa interação entre o loop de eventos, a pilha de chamadas e a fila de retorno de chamada. As operações assíncronas não bloqueiam a pilha de chamadas, o que significa que o JavaScript pode continuar executando outro código enquanto aguarda a conclusão das tarefas em segundo plano.
Considere o seguinte exemplo com uma função setTimeout:
console.log('Start'); setTimeout(() => { console.log('This runs after 2 seconds'); }, 2000); console.log('End');
Aqui está o que acontece passo a passo:
JavaScript imprime "Iniciar".
A função setTimeout é chamada, mas em vez de bloquear a execução por 2 segundos, ela é enviada para a API Web, onde é executada em segundo plano.
JavaScript imprime "End", continuando sua execução sem esperar que setTimeout seja concluído.
Após 2 segundos, a função de retorno de chamada dentro de setTimeout é colocada na fila de retorno de chamada.
O loop de eventos verifica se a pilha de chamadas está vazia (o que está), então envia a função de retorno de chamada para a pilha e a executa, imprimindo "Isso é executado após 2 segundos".
Outra maneira popular de lidar com tarefas assíncronas no JavaScript moderno é por meio de Promises e da sintaxe async/await, que ajuda a tornar o código mais legível, evitando retornos de chamada profundamente aninhados (também conhecidos como "inferno de retorno de chamada").
Uma promessa representa a eventual conclusão (ou falha) de uma operação assíncrona e seu valor resultante. Aqui está um exemplo:
const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise resolved!'); }, 1000); }); promise.then(result => { console.log(result); // Output after 1 second: 'Promise resolved!' });
Em vez de confiar em retornos de chamada, podemos usar then() para lidar com o que acontece quando a promessa é resolvida. Se quisermos lidar com código assíncrono de uma maneira mais síncrona, podemos usar async/await:
async function asyncExample() { const result = await promise; console.log(result); // Output after 1 second: 'Promise resolved!' } asyncExample();
Isso torna o código mais limpo e fácil de entender, permitindo-nos "aguardar" a conclusão das tarefas assíncronas antes de passar para a próxima linha de código, mesmo que o JavaScript permaneça sem bloqueio nos bastidores.
Pilha de chamadas: onde o código síncrono é executado.
Web APIs/Node.js APIs: ambientes externos onde tarefas assíncronas (como solicitações de rede) são tratadas.
Fila de retorno de chamada: uma fila onde os resultados da tarefa assíncrona aguardam para serem enviados para a pilha de chamadas para execução.
Loop de eventos: o sistema que coordena entre a pilha de chamadas e a fila de retorno de chamada, garantindo que as tarefas sejam tratadas na ordem correta.
A natureza de thread único do JavaScript pode parecer limitante à primeira vista, mas seus recursos assíncronos permitem gerenciar múltiplas tarefas com eficiência. Por meio de mecanismos como loop de eventos, filas de retorno de chamada e promessas, o JavaScript é capaz de lidar com operações complexas e sem bloqueio, mantendo um estilo de codificação intuitivo e de aparência síncrona.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3