> For the complete documentation index, see [llms.txt](https://uclsanca.gitbook.io/learn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://uclsanca.gitbook.io/learn/web-basico/javascript/event-loop.md).

# Event Loop

## O que é o *Event Loop*?

Um dos principais fatos sobre o JavaScript é que ele é uma linguagem inerentemente [*single thread*](https://pt.wikipedia.org/wiki/Thread_%28computa%C3%A7%C3%A3o%29), isto é, em qualquer instante de tempo apenas um comando pode estar sendo executado. Essa é uma das características principais da linguagem, independente de onde ela esteja sendo executada. Além disso, o JavaScript é uma linguagem *assíncrona*, isto é, a ordem de execução das funções não é sempre bem definida. Isso quer dizer que, dependendo de como o código for escrito, cada execução do código pode ter uma ordem diferente de execução de suas funções.

Como o JavaScript é *single thread* e *assíncrono*, apenas uma função pode estar sendo executada em qualquer momento, mas a ordem de execução delas deve ser definida durante a execução do código. Assim, o *Event Loop* (tradução: *Ciclo de Eventos*) é o mecanismo que o JavaScript usa para escolher qual será a próxima função a ser executada.

## O problema

Numa página web, quase sempre que o usuário faz uma ação, a interface deve ser atualizada de alguma forma. Seja para mudar a cor de um link que foi visitado ou para descer o *scroll* da página. Entretanto, em todos os *browsers* modernos, a interface não pode ser atualizada enquanto houver código JavaScript sendo executado, e não se pode executar código JavaScript enquanto a interface estiver sendo atualizada (os dois não podem ser feitos ao mesmo tempo).

Assim, se nosso código JavaScript for muito demorado, a tela do usuário ficará travada e irresponsiva, causando uma péssima experiência. Veja um exemplo de código que tem esse comportamento:

```markup
<html>
    <body>
        <button onClick="click()">Click me!</button>
        <script>
            function click () {
                // Função ficticia que faz uma requisição HTTP para um servidor.
                fetchDataFromServer();

                alert('Operação terminada!');
            }
        </script>
    </body>
</html>
```

No exemplo acima, quando o usuário clicar no botão, toda a interface ficará travada até a função `click` terminar, o que pode demorar múltiplos segundos.

## A solução

Para mitigar o problema descrito acima, foi-se desenvolvida a ideia de "agendar" a execução de funções num momento futuro, liberando o *browser* para atualizar a interface do usuário ou executar outras partes do código JavaScript.

No caso do exemplo descrito no problema, a maior parte da "demora" numa requisição HTTP vem da espera pela resposta, e enquanto se espera por essa resposta outra parte do código poderia estar sendo executada (ou a interface do usuário poderia estar sendo atualizada). Outro exemplo parecido é num temporizador, onde uma função só deve ser executada depois de uma quantidade determinada de tempo. Enquanto se espera para executar essa função, o *browser* poderia ser liberado para terminar outras tarefas.

Assim, algumas funções disponibilizadas pelo *browser* recebem outras funções como argumento (também conhecidas como *Callbacks*), que serão executadas apenas quando a operação da primeira função terminar. Veja esse exemplo:

```markup
<html>
    <body>
        <button onClick="click()">Click me!</button>
        <script>
            function timerEnded () {
                alert('O temporizador acabou!');
            }

            function click () {
                // Espera 5 segundos para executar a função "timerEnded"
                setTimeout(timerEnded, 5000);
            }
        </script>
    </body>
</html>
```

Aqui, quando o usuário clicar no botão, o código vai esperar 5 segundos para mostrar um alerta. Enquanto esse tempo passa, a interface do usuário não ficara travada ou irresponsiva. Isso é porque a função `setTimeout` apenas "agenda" a execução da sua *callback* para quando o temporizador de 5 segundos terminar.

Veja esse outro exemplo, mas dessa vez fazendo uma requisição.

```markup
<html>
    <body>
        <button onClick="click()">Click me!</button>
        <script>
            function responseTextFinished (responseText) {
                alert(responseText);
            }

            function responseReceived (response) {
                // Tenta extrair o texto da requisição HTTP
                response.text().then(responseTextFinished);
            }

            function click () {
                // Faz uma requisição HTTP
                fetch('https://my-server-url.com').then(responseReceived);
            }
        </script>
    </body>
</html>
```

Este é um exemplo um pouco mais complicado, mas que essencialmente faz a mesma coisa que o temporizador. Nesse caso, o código faz uma requisição para um servidor, e agenda a função `responseReceived` para ser executada quando uma resposta do servidor for recebida. Essa função, por sua vez, tenta extrair o corpo da resposta na forma de texto, e agenda a função `responseTextFinished` para ser executada quando esse texto estiver pronto. Durante todo esse processo, enquanto essas operações estavam sendo feitas, o *browser* estava livre para atualizar a interface do usuário.

## Como funciona

### As ferramentas

Para gerenciar as operações e funções agendadas, o browser usa três construtos: a "*Call Stack*", as "*Web APIs*" e a "*Queue*".

A *Call Stack* (tradução: *Pilha de chamadas*) é uma pilha de funções que estão sendo executadas no atual instante. Quando uma função do JavaScript é chamada, ela é posta no topo da *Call Stack*. Quando uma função do JavaScript termina de executar, ela é removida da *Call Stack*. Se a *Call Stack* estiver vazia, quer dizer que nenhuma função está sendo executada no momento.

As *Web APIs* são funções especiais que realizam tarefas complexas por trás dos panos. A maior parte dessas funções são implementadas de forma que utilizam eficientemente os recursos do computador. Essas funções não pertencem ao JavaScript em si, mas são disponibilizadas pelo ambiente de execução (no nosso caso, o *browser*). Exemplos de *Web APIs* são: `fetch`, `setTimeout` ou `setInterval`. Você pode ver uma lista das *Web APIs* mais amplamente implementadas nos *browsers* modernos [aqui](https://developer.mozilla.org/en-US/docs/Web/API).

A *Queue* (tradução: *Fila*) é uma fila de *callbacks* que estão prontas para serem imediatamente executadas, mas que ainda estão aguardando uma oportunidade.

### O fluxo

Tudo começa com a primeira execução do código JavaScript. Primeiro, o código que está escrito na página é embrulhado numa grande função e posto no início da *Call Stack*. Como a *Call Stack* é a pilha que define qual função está sendo atualmente executada, o código fonte é executado, linha a linha.

Eventualmente, algumas linhas fazem chamadas a algumas *Web APIs*. Por exemplo, podem-se ter sido feitas chamadas de `setTimeout`, ou `fetch`. Essas *Web APIs* sempre recebem uma *callback* e alguns outros parâmetros. Essas *callbacks* vão ser "guardadas" até que a *Web API* termine a sua tarefa. Uma vez que essa tarefa é terminada, a sua callback é imediatamente enviada para o fim da *Queue*.

Por último vem o trabalho do *Event Loop*. Pode-se pensar nele como um *loop* infinito que constantemente verifica se a interface do usuário precisa ser atualizada, se há algo na *Queue* esperando para ser executado, e se a *Call Stack* está vazia. A sua lógica pode ser bem descrita de acordo com o seguinte pseudo-código:

```javascript
function eventLoop () {
    while (true) {
        // Sempre antes de olhar para a Queue, verifica se a interface precisa ser atualizada.
        if (shouldUpdateUserInterface()) updateUserInterface();

        // Apenas age se houver elementos na Queue e se a callStack esiver vazia.
        if (queue.isNotEmpty() && callStack.isEmpty()) {
            // Transfere o elemento do início da Queue para a Call Stack.
            queue.sendFirstElementToCallStack();
        }

        // Executa a função no topo da Call Stack.
        // Note que quando essa função terminar de executar, ela será automaticamente removida da Call Stack, deixando-a vazia de novo.
        callStack.executeFunctionOnTop();
    }
}
```

### Um exemplo simples

Considere o código abaixo:

```javascript
console.log('Início');

function sayHi () {
    console.log('Oi!');
}

// Agenda a função "sayHi" para executar em 5 segundos
setTimeout(sayHi, 5000);

console.log('Fim do código principal');
```

Nesse exemplo, a primeira coisa que acontece é o código ser imediatamente movido para a *Call Stack*, e ser imediatamente executado. Assim, a primeira linha imprime a palavra "Início". Na terceira linha, declaramos a função `sayHi`. Na oitava linha, fazemos uma chamada para a *Web API* `setTimeout`, que agenda a *callback* `sayHi` para ser executada em 5 segundos. Por fim, na décima linha, imprime-se a string "Fim do código principal".

Ao finalizar a execução desse código, a *Call Stack* ficará vazia, e o *Event Loop* começará o seu trabalho de constantemente verificar se há algo na *Queue*, pronto para mover para a *Call Stack*. Nesse caso, a única coisa que o nosso código ainda está fazendo é esperar a *Web API* do `setTimeout` terminar a contagem do temporizador de 5 segundos, enquanto a *Call Stack* e a *Queue* ficam vazias. Logo, pelos próximo 5 segundos, nada acontece.

Passados os 5 segundos, a *Web API* do `setTimeout` termina o seu trabalho e move a *callback* `sayHi` para a *Queue*. O *Event Loop*, que durante todo este tempo estava esperando algo aparecer na *Queue*, finalmente vê que a *Call Stack* está vazia e que há algo na *Queue*. Assim, o *Event Loop* move a *callback* `sayHi` da *Queue* para a *Call Stack* e a executa.

Finalmente, com a função `sayHi` na *Call Stack* e sendo executada, o `console.log` da linha 4 é executado, e a string "Oi!" aparece no *console*. Assim, a impressão final deste código é:

```
Início
Fim do código principal
Oi!
```

### Um exemplo mais complicado

```javascript
console.log('Início');

// simpleFetch é uma função fictícia (não existe).
// Apenas imagine que ela faz uma requisição HTTP.

simpleFetch ('http://my-server.com', () => console.log('Requisição 1 concluída'));
simpleFetch ('http://my-server.com', () => console.log('Requisição 2 concluída'));
simpleFetch ('http://my-server.com', () => console.log('Requisição 3 concluída'));

console.log('Fim do código principal');
```

Neste exemplo fazemos 3 requisições HTTP diferentes para o nosso servidor, imprimindo uma string única ao terminar. O processo básico é o mesmo:

* Código movido para a *Call Stack*, com sua execução iniciada.
* As três requisições HTTP são iniciadas (através de uma *Web API*, com suas respectivas *callbacks*.
* A execução do código principal termina, e a *Call Stack* fica vazia.
* As requisições terminam, e suas *callbacks* são movidas para a *Queue*.
* O *Event Loop* move as *callbacks* da *Queue* para a *Call Stack*, e inicia a sua execução.

Mas nesse exemplo há algo de mais interessante: são três requisições acontecendo ao mesmo tempo, sem ter ideia de qual vai acabar primeiro. É possível que as duas primeiras levem 3 segundos enquanto a terceira leve 15 segundos. É possível que todas terminem no mesmo exato momento. É possível que uma termine enquanto a *callback* da outra está sendo executada. São inúmeras possibilidades.

Em casos como esse, quem terminar primeiro poderá empurrar a sua *callback* para a *Queue* primeiro. E a ordem de execução das *callbacks* é a ordem de chegada delas na *Queue*. Mesmo que as três requisições terminem ao mesmo tempo, alguma delas será tratada primeiro, enquanto a *callback* da outras espera na *Queue* a *Call Stack* se liberar.

## Resumo

Neste capítulo, vimos:

* Os tipos de problemas que inspiraram a invenção do *Event Loop*
* A solução dos problemas, usando *Web APIs*.
* Como o *Event Loop* funciona
* Alguns exemplos de códigos que usaram *Web APIs*.
