# Funções Assíncronas

## Visão geral

A maior parte do código na sua cena é executada de forma síncrona usando um único thread. Isso significa que os comandos são executados sequencialmente, linha por linha. Cada comando precisa primeiro aguardar que o comando anterior termine de executar antes de poder começar.

Até mesmo as funções nos sistemas da sua cena são executadas uma a uma, seguindo uma [ordem de prioridade](https://docs.decentraland.org/creator/content-creator-pt/arquitetura/systems#system-execution-order).

Executar código de forma síncrona garante consistência, pois você sempre pode ter certeza da ordem em que os comandos no seu código são executados.

Por outro lado, sua cena precisa ser atualizada muitas vezes por segundo, construindo o próximo frame. Se uma parte do seu código demorar demais para responder, então todo o thread principal fica preso e isso resulta em taxas de quadros com lag.

É por isso que, em alguns casos, você quer que alguns comandos sejam executados de forma assíncrona. Isso significa que você pode iniciar uma tarefa em um novo thread e, enquanto isso, o thread principal pode continuar executando as próximas linhas de código.

Isso é especialmente útil para tarefas que dependem de serviços externos que podem demorar a responder, já que você não quer que esse tempo ocioso aguardando a resposta bloqueie outras tarefas.

Por exemplo:

* Ao recuperar dados de uma API REST
* Ao executar uma transação na blockchain

{% hint style="warning" %}
**📔 Nota**: Tenha em mente que vários frames da sua cena podem ser renderizados antes que a tarefa termine de executar. Garanta que o código da sua cena seja flexível o suficiente para lidar com os cenários intermediários enquanto a tarefa assíncrona está sendo concluída.
{% endhint %}

## Executar uma função async

Marque qualquer função como `async` para que ela seja executada em um thread separado do thread principal da cena sempre que for chamada.

```ts
// declarar função async
async function myAsyncTask() {
	// executar passos da função
}

// chamar função async
myAsyncTask()

// o restante do código continua sendo executado
```

## A função executeTask

A `executeTask()` função executa uma função lambda de forma assíncrona, em um thread separado do thread principal da cena. `executeTask()` nos permite declarar e executar a função tudo em uma mesma instrução.

```ts
executeTask(async () => {
	let data = await myAsyncTask()
	console.log(data)
})

// o restante do código continua sendo executado
```

## A função then

A `then` função recebe uma função lambda como argumento, que só é executada uma vez que a instrução anterior seja concluída. Essa função lambda pode opcionalmente ter entradas que são mapeadas a partir do que a instrução anterior retorna.

```ts
myAsyncTask().then((data) => {
	console.log(data)
})
```

{% hint style="warning" %}
**📔 Nota**: Geralmente é melhor usar o `executeTask` approach rather than the `then` function. In this example, the scene won't be considered fully loaded by the explorer till the `myAsyncTask()` function is completed, which may affect load times. Also, if relying too much on the `then` function at multiple nested levels, you can end up with what's known as "callback hell", where the code can become very hard to read and maintain.
{% endhint %}

## Funções PointerEvents e RayCast

Quando sua cena usa um `PointerEvent` ou um `RayCast` componente, os cálculos de colisões são realizados de forma assíncrona no engine. O engine então retorna um evento de resultados para a cena, que pode chegar um ou vários ticks do game loop depois de quando o evento foi invocado.

Você então precisa criar um system para processar esses resultados no frame em que eles chegam.

{% hint style="warning" %}
**📔 Nota**: Se você tratar cliques via o [**Registrar um callback**](https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/interatividade/eventos-de-botao/register-callback) approach, you don't need to explicitly create a system to handle this, but the same occurs in the background.
{% endhint %}

Veja [eventos de clique](https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/interatividade/eventos-de-botao/click-events) e [raycasting](https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/interatividade/raycasting).

{% hint style="info" %}
**💡 Dica**: Se o processamento dos resultados de um raycast requer muitos cálculos (como executar um algoritmo de path-finding) você pode querer executar esse cálculo em uma função assíncrona.
{% endhint %}

## A instrução await

Um `await` a instrução força a execução a aguardar uma resposta antes de passar para a próxima linha de código. `await` instruções só podem ser usadas dentro de um bloco de código async.

```ts
// declarar função
async function myAsyncTask() {
	try {
		let response = await fetch(callUrl)
		let json = await response.json()
		console.log(json)
	} catch {
		console.log('failed to reach the URL')
	}
}

// chamar função
myAsyncTask()

// O restante do código continua sendo executado
```

O exemplo acima executa uma função que inclui um `fetch()` operation to retrieve data from an external API. The `fetch()` operation is asynchronous, as we can't predict how long the server will take to respond. However, the next line needs the output of this operation to be ready before we can parse it as a json. The `await` statement here ensures that the next line will only run once that operation has returned a value. Similarly, the `response.json()` function is also asynchronous, but the next line needs the json to be parsed before it can log it. The second `await` statement forces the next line to only be called once the parsing of the json is finished, however long it takes.

## Definir um Timeout para a chamada de uma função

Use `setTimeout` para esperar algum tempo antes de certas linhas de código serem executadas. Isso recebe dois argumentos:

* A função a ser executada
* A quantidade de milissegundos a esperar antes de executar essa função

O exemplo abaixo espera 1000 milissegundos (igual a 1 segundo) antes de executar uma função simples que registra uma mensagem no console.

```ts
import { timers } from '@dcl/sdk/ecs'

console.log('Isso é impresso imediatamente')

timers.setTimeout(() => {
	// função a executar após o atraso
    console.log('Isso é impresso após 1 segundo')
}, 1000)
```

A `clearTimeout` pode ser usado para cancelar a execução de uma `setTimeout` função que ainda está aguardando para ser executada. Ao criar a `setTimeout` função, pegue uma referência para a função, que você pode então passar para `clearTimeout`. Neste caso, a variável `intervalId` é obtida ao fazer o `setTimeout`, e então passada para `clearTimeout` para cancelá-la.

```ts
import { timers } from '@dcl/sdk/ecs'

const timeoutId = timers.setTimeout(() => {
    console.log('Espere 1 segundo antes de executar esta função')
}, 1000)

timers.clearTimeout(intervalId)
```
