Você já se perguntou como o Javascript funciona? Parte 2 — Event loop, Filas e Programação Assíncrona

Thais Ribeiro
luizalabs
Published in
5 min readFeb 28, 2020

Olá pessoas incríveis da internet, estou aqui novamente e como sempre aprendendo e compartilhando com vocês.

Vocês já leram o post anterior? Falei sobre o fato do Javascript ser single-thread, mostrei como a call stack funciona e compreendemos um pouco como funciona o mecanismo Javascript. Acredite, eu ficaria horas e horas falando sobre esse tópico, mas o intuito não é esse! Chega de me estender por aqui, quem quiser saber mais é só acessar o link: Você já se perguntou como o Javascript funciona? Call Stack e visão geral do mecanismo.

O título já dá um pouco de spoiler do que vamos falar, então vou começar pelo event loop, com uma analogia.

Eu vou convidar uma telefonista para nos ajudar aqui, beleza?

Vamos chamar a nossa telefonista de dona Loop de Eventos e é ela que vai ficar monitorando a nossa pilha de chamadas e nossa fila de tarefas. Quando ela ver que a pilha está vazia e que na fila existem pendências, ela vai ser responsável por empurrar essa tarefa para a pilha executar.

Vamos analisar o seguinte código com funções síncronas:

function segunda (){
console.log('World');
}
function primeira (){
console.log('Hello');
segunda();
console.log('Fim');
}
primeira();

Como ficaria a execução desse bloco de código na nossa pilha de chamada?

Observem a ordem de execução do nosso bloco de código: console.log são funções executadas de forma rápida e colocadas imediatamente na pilha de chamadas por serem funções síncronas. Agora vamos alterar nosso bloco de código inserindo a função assíncrona setTimeout:

function primeira (){
console.log('Hello');
setTimeout(function segunda(){console.log('World')}, 0);
console.log('Fim');
}

Estávamos esperando que a saída nos retornasse Hello, World e Fim, mas não foi o que aconteceu, não é mesmo? Mas por qual motivo?

Lembra que eu disse que setTimeout é uma função assíncrona? Todos os retornos de chamadas assíncronas não são executadas imediatamente, e sim um tempo depois e o responsável por isso é o event loop (ou, na nossa analogia, a telefonista).

“Alô senhor, é a dona Loop de Eventos e eu vou suspender a execução da segunda função por enquanto, mas continue na linha, assim que você terminar com as outras tarefas, eu retorno com essa função, beleza?”

Vamos ver como ficaria a execução desse bloco de código:

Deu para entender como funciona o event loop? O loop dá prioridade para a pilha de chamadas e uma vez que não tem nada lá, ele busca se tem algo pendente na fila de tarefas. É importante sabermos também que a fila não tem somente essa responsabilidade, pois é aqui também onde ficam os eventos iniciados pelo usuário, funções que precisam ser executadas como é o nosso caso e também eventos do DOM como o onLoad.

“Thais, mas se o Javascript só faz uma coisa por vez, tem chances de ter bloqueio se eu fizer uma função recursiva ou longa demais e pode ser que aconteça de não executar na ordem que eu quero. Então qual a vantagem e como lidar com esse loop de eventos?”

Ter uma só responsabilidade tem suas limitações. Isso pode ser útil, pois simplifica muito como se programa ao não ter que se preocupar com problemas de simultaneidade, mas é preciso prestar atenção em como se escreve o código. Mas, pra isso, o ECMAScript2015/ES6 pode te ajudar!

Nós não temos que ficar esperando por funções como setTimeout, porque atualmente conseguimos trabalhar com o conceito de Job Queue. Introduzido pelo ES6, esse conceito é usado por Promises e, como eu sou o tipo de pessoa que adora usar analogias para explicar, vamos lá?

É sábado e você quer ir jogar fliperama. Você chega no local e a responsável (fila de mensagem) te coloca no final da fila, atrás de todas as pessoas. Mas você foi esperto e comprou um cartão de passe rápido (fila de trabalho), que permite que você jogue outra vez logo após terminar a primeira partida.

Analisando o acontecimento acima, conseguimos entender a importância das Promises — isso é javascript assíncrono. Usando Javascript assíncrono nós temos a opção de executar solicitações longas sem bloquear a thread principal.

Alguém aqui já usou AJAX? AJAX por default é assíncrono, tanto que se setar “async: false” para nossa requisição, vamos ter problemas. Não façam isso em casa. Quem já usou sabe que são nas funções de retorno (callback) que são feitas as operações embasadas no resultado que tivemos naquela requisição.

Agora usando Promises:

function soma (x, y){
return Promise.all([x,y]).then(value => value[0] + value[1])
}
soma(10,10).then(sum => console.log(sum))

Promises nos ajudam a trabalhar com código assíncrono de uma maneira muito mais organizada.

E Async/Await?

Se com Promises conseguimos escrever códigos assíncronos mais organizados, vocês precisam conhecer Async/Await. Isso funciona da seguinte forma: você define uma função usando async e essa função retorna um objeto AsyncFunction; quando essa função é executada, ela retorna uma Promise, e se em alguma parte da função usamos o await para chamarmos outra Promise, ela vai pausar a execução da função, aguardar a resolução da Promise de dentro e em seguida retorna a execução. Parece complexo, né? Dê uma olhadinha no código para ficar mais fácil:

async function logFetch() {
try {
const response = await fetch('http://example.api/endpoint1');
console.log(await response.text());
}
catch (err) {
console.log('fetch failed', err);
}
}

Bom, por hoje é só, espero que tenham curtido passar esse tempo comigo e fiquem atentos aos próximos artigos.

Tchau ❤

--

--

Thais Ribeiro
luizalabs

Software Engineer at Luizalabs, Community Leader at frontInUdi & Blogger