# Funciones asíncronas

## Descripción general

La mayor parte del código en tu scene se ejecuta de forma síncrona usando un solo hilo. Eso significa que los comandos se ejecutan secuencialmente línea por línea. Cada comando debe esperar primero a que el comando anterior termine de ejecutarse antes de poder comenzar.

Incluso las funciones en los systems de tu scene se ejecutan una por una, siguiendo un [orden de prioridad](/creator/content-creator-es/scenes-sdk7/arquitectura/systems.md#system-execution-order).

Ejecutar código de forma síncrona garantiza consistencia, ya que siempre puedes estar seguro de que conocerás el orden en que se ejecutan los comandos de tu código.

Por otro lado, tu scene necesita actualizarse muchas veces por segundo para construir el siguiente frame. Si una parte de tu código tarda demasiado en responder, entonces todo el hilo principal se bloquea y esto provoca una tasa de frames lenta.

Por eso, en algunos casos quieres que algunos comandos se ejecuten de forma asíncrona. Esto significa que puedes iniciar una tarea en un nuevo hilo y, mientras tanto, el hilo principal puede seguir ejecutando las siguientes líneas de código.

Esto es especialmente útil para tareas que dependen de servicios externos que pueden tardar en responder, ya que no quieres que ese tiempo de espera ocioso bloquee otras tareas.

Por ejemplo:

* Al recuperar datos de una API REST
* Al realizar una transacción en la blockchain

{% hint style="warning" %}
**📔 Nota**: Ten en cuenta que varias frames de tu scene podrían renderizarse antes de que la tarea termine de ejecutarse. Asegúrate de que el código de tu scene sea lo suficientemente flexible como para manejar los escenarios intermedios mientras se completa la tarea asíncrona.
{% endhint %}

## Ejecutar una función async

Marca cualquier función como `async` para que se ejecute en un hilo separado del hilo principal de la scene cada vez que se llame.

```ts
// declarar función async
async function myAsyncTask() {
	// ejecutar los pasos de la función
}

// llamar a la función async
myAsyncTask()

// el resto del código sigue ejecutándose
```

## La función executeTask

El `executeTask()` la función ejecuta una función lambda de forma asíncrona, en un hilo separado del hilo principal de la scene. `executeTask()` nos permite declarar y ejecutar la función todo en una misma instrucción.

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

// el resto del código sigue ejecutándose
```

## La función then

El `then` la función toma una función lambda como argumento, que solo se ejecuta una vez que la instrucción anterior ha terminado. Esta función lambda puede tener opcionalmente entradas que se asignan a partir de lo que devuelva la instrucción anterior.

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

{% hint style="warning" %}
**📔 Nota**: En general, es mejor usar el enfoque de `executeTask` en lugar de la `then` función. En este ejemplo, el explorer no considerará que la scene se ha cargado por completo hasta que la `myAsyncTask()` función se complete, lo que puede afectar los tiempos de carga. Además, si dependes demasiado de la `then` función en múltiples niveles anidados, puedes terminar con lo que se conoce como "callback hell", donde el código puede volverse muy difícil de leer y mantener.
{% endhint %}

## Funciones PointerEvents y RayCast

Cuando tu scene usa un `PointerEvent` o un `RayCast` component, los cálculos de colisiones se realizan de forma async en el engine. Luego, el engine devuelve un evento de resultados a la scene, que puede llegar uno o varios ticks del game loop después de que se invocó el evento.

Entonces necesitas crear un system para procesar estos resultados en el frame en que llegan.

{% hint style="warning" %}
**📔 Nota**: Si manejas clics mediante el enfoque de [**Registrar un callback**](/creator/content-creator-es/scenes-sdk7/interactividad/eventos-de-button/register-callback.md) no necesitas crear explícitamente un system para manejar esto, pero ocurre lo mismo en segundo plano.
{% endhint %}

Consulta [eventos de clic](/creator/content-creator-es/scenes-sdk7/interactividad/eventos-de-button/click-events.md) y [raycasting](/creator/content-creator-es/scenes-sdk7/interactividad/raycasting.md).

{% hint style="info" %}
**💡 Consejo**: Si el procesamiento de los resultados de un raycast requiere muchos cálculos (como ejecutar un algoritmo de búsqueda de rutas), puede que quieras ejecutar ese cálculo en una función asíncrona.
{% endhint %}

## La instrucción await

Un `await` la instrucción obliga a que la ejecución espere una respuesta antes de pasar a la siguiente línea de código. `await` las instrucciones solo pueden usarse dentro de un bloque de código async.

```ts
// declarar función
async function myAsyncTask() {
	try {
		let response = await fetch(callUrl)
		let json = await response.json()
		console.log(json)
	} catch {
		console.log('no se pudo alcanzar la URL')
	}
}

// llamar a la función
myAsyncTask()

// El resto del código sigue ejecutándose
```

El ejemplo anterior ejecuta una función que incluye una `fetch()` operación para recuperar datos de una API externa. La `fetch()` operación es asíncrona, ya que no podemos predecir cuánto tiempo tardará el server en responder. Sin embargo, la siguiente línea necesita que el resultado de esta operación esté listo antes de poder analizarlo como un json. La `await` instrucción aquí garantiza que la siguiente línea solo se ejecutará una vez que esa operación haya devuelto un valor. De manera similar, la `response.json()` función también es asíncrona, pero la siguiente línea necesita que el json se analice antes de poder registrarlo. La segunda `await` instrucción obliga a que la siguiente línea solo se llame una vez que termine el análisis del json, sin importar cuánto tarde.

## Establecer un timeout para una llamada a función

Usa `setTimeout` para esperar un tiempo antes de que se ejecuten ciertas líneas de código. Esto toma dos argumentos:

* La función a ejecutar
* La cantidad de milisegundos a esperar antes de ejecutar esa función

El ejemplo de abajo espera 1000 milisegundos (equivalente a 1 segundo) antes de ejecutar una función simple que registra un mensaje en la consola.

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

console.log('Esto se imprime de inmediato')

timers.setTimeout(() => {
	// función que se ejecutará después del retraso
    console.log('Esto se imprime después de 1 segundo')
}, 1000)
```

El `clearTimeout` se puede usar para cancelar la ejecución de una `setTimeout` función que todavía está esperando para ejecutarse. Al crear la `setTimeout` función, toma una referencia a la función, que luego puedes pasar a `clearTimeout`. En este caso, la variable `intervalId` se obtiene al hacer la `setTimeout`, y luego se pasa a `clearTimeout` para cancelarla.

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

const timeoutId = timers.setTimeout(() => {
    console.log('Espera 1 segundo antes de ejecutar esta función')
}, 1000)

timers.clearTimeout(intervalId)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/patrones-de-programacion/async-functions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
