1.1 Conceitos básicos de assincronismo
O assincronismo no JavaScript permite executar tarefas em segundo plano, sem bloquear o fluxo principal de execução. Isso é especialmente importante para tarefas que podem levar tempo significativo, como requisições de rede, leitura de arquivos e timers. Agora vamos dar uma olhada nos conceitos principais de programação assíncrona em JavaScript e dar exemplos de uso.
Natureza single-threaded do JavaScript
JavaScript é uma linguagem single-threaded: ou seja, ela executa o código sequencialmente em um único thread. No entanto, operações assíncronas permitem a execução de tarefas em segundo plano, liberando o fluxo principal para outras tarefas.
Event Loop
O Event Loop é um mecanismo chave que permite ao JavaScript lidar com tarefas assíncronas. O Event Loop gerencia a fila de mensagens (Message Queue) e a fila de microtarefas (Microtask Queue), garantindo a execução das operações assíncronas.
- Fila de mensagens: contém tarefas como handlers de eventos, requisições de rede e timers. As tarefas nessa fila são executadas sequencialmente.
- Fila de microtarefas: contém tarefas com prioridade mais alta em relação às tarefas na fila de mensagens. Exemplos incluem a finalização de promises e chamadas de callbacks em microtarefas.
O Event Loop verifica constantemente ambas as filas e executa tarefas delas quando o fluxo principal está livre.
Operações assíncronas
As operações assíncronas permitem executar tarefas em segundo plano. Principais exemplos de operações assíncronas incluem:
- Timers (
setTimeout
,setInterval
) - Handlers de eventos
- Requisições de rede (por exemplo,
XMLHttpRequest
,Fetch API
) - Leitura/escrita de arquivos (em Node.js)
Vamos conferir alguns exemplos de operações assíncronas.
1.2 Timers
Timers permitem executar tarefas com atraso ou através de intervalos regulares de tempo.
Exemplo de uso de setTimeout
Neste exemplo, setTimeout
configura a execução de uma função após 2 segundos. Como resultado, primeiro é exibido
Start
e End
, e depois de 2 segundos é exibido Executed after 2 seconds
.
console.log('Start');
setTimeout(() => {
console.log('Executed after 2 seconds');
}, 2000);
console.log('End');
Exemplo de uso de setInterval
Neste exemplo, setInterval
executa a função a cada segundo, incrementando o contador e exibindo seu valor.
Quando o contador atinge 5, o intervalo é limpo com clearInterval
:
let counter = 0;
const intervalID = setInterval(() => {
counter++;
console.log(`Counter: ${counter}`);
if (counter >= 5) {
clearInterval(intervalID);
}
}, 1000);
1.3 Handlers de eventos
Handlers de eventos permitem executar código em resposta a ações do usuário ou outros eventos.
Exemplo de uso de handlers de eventos
Neste exemplo, um handler de evento click
é adicionado a um botão. Quando o usuário clica no botão,
é exibida a mensagem Button clicked!
:
<!DOCTYPE html>
<html>
<head>
<title>Event Handler Example</title>
</head>
<body>
<button id="myButton">Click me</button>
<script>
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
});
</script>
</body>
</html>
1.4 Requisições de rede
Requisições de rede permitem fazer requisições HTTP assíncronas para o servidor.
Exemplo de uso de XMLHttpRequest
Neste exemplo, é criada uma requisição GET assíncrona para uma API, e quando a requisição é completada, a resposta é exibida no console:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
}
};
xhr.send();
1.5 Event Loop em ação
Para entender melhor como o Event Loop funciona, vamos olhar o seguinte exemplo:
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
});
setTimeout(() => {
console.log('Timeout 2');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 2');
});
console.log('End');
A saída esperada será a seguinte:
Start
End
Promise 1
Promise 2
Timeout 1
Timeout 2
Neste exemplo, primeiro são executadas as operações síncronas (console.log('Start')
e console.log('End')
). Em seguida,
são executadas as microtarefas (handlers dos promises), e só depois são executadas as tarefas da fila de mensagens (setTimeout
).
GO TO FULL VERSION