> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/bian-cheng-mo-shi/async-functions.md).

# 异步函数

了解何时以及如何在你的场景代码中运行异步函数。

## 概览

你场景中的大部分代码使用单线程同步运行。这意味着命令会按行逐个顺序执行。每个命令都必须先等待前一个命令执行完成，才能开始执行。

即使是场景系统中的函数也会逐个执行，遵循一个 [优先级顺序](/creator/content-creator-zh/chang-jing-sdk7/jia-gou/systems.md#system-execution-order).

同步运行代码可以确保一致性，因为你总能确定代码中的命令会按什么顺序执行。

另一方面，你的场景需要每秒更新多次，以构建下一帧。如果代码中的某一部分响应时间过长，那么整个主线程就会被卡住，从而导致帧率下降、出现卡顿。

因此，在某些情况下，你会希望某些命令异步运行。这意味着你可以先启动一个任务，同时场景可以继续执行后面的代码行。场景仍然在单线程上运行，但当异步任务等待响应时，其余代码不会被阻塞。

这对依赖外部服务、且响应可能需要时间的任务尤其有用，因为你不希望等待响应的空闲时间阻塞其他任务。

例如：

* 从 REST API 获取数据时
* 在区块链上执行交易时

{% hint style="warning" %}
**📔 注意**: 请记住，在任务完成执行之前，你的场景可能已经渲染了好几帧。请确保你的场景代码足够灵活，能够在异步任务完成期间处理中间状态。
{% endhint %}

## 运行一个异步函数

将任意函数标记为 `异步` ，使其异步运行，在等待期间不会阻塞场景中的其余代码。

```ts
// 声明异步函数
async function myAsyncTask() {
	// 执行函数步骤
}

// 调用异步函数
myAsyncTask()

// 其余代码继续执行
```

## executeTask 函数

该 `executeTask()` 该函数会异步执行一个 lambda 函数。 `executeTask()` 允许我们在同一个语句中声明并执行函数。

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

// 其余代码继续执行
```

## then 函数

该 `then` 函数将一个 lambda 函数作为参数传入，该 lambda 只有在前一个语句执行完成后才会被执行。这个 lambda 函数可以选择性地带有输入参数，这些参数会从前一个语句返回的内容中映射而来。

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

{% hint style="warning" %}
**📔 注意**: 通常更适合使用 `executeTask` 方法，而不是 `then` 函数。如果你过度依赖 `then` 函数并在多个嵌套层级中使用，就可能会出现所谓的“回调地狱”，代码会变得非常难以阅读和维护。
{% endhint %}

## PointerEvents 和 RayCast 函数

当你的场景使用 `PointerEvent` 或 `RayCast` 组件时，碰撞计算会在引擎中异步完成。随后引擎会向场景返回一个结果事件，而这个事件可能会在触发该事件后的一个或多个游戏循环 tick 之后才到达。

然后你需要创建一个系统，在结果到达的那一帧中对这些结果进行处理。

{% hint style="warning" %}
**📔 注意**: 如果你通过 [**注册回调**](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/register-callback.md) 方式处理点击事件，就不需要显式创建一个系统来处理它，但相同的过程仍然会在后台发生。
{% endhint %}

参见 [点击事件](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/click-events.md) 和 [射线投射](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/raycasting.md).

{% hint style="info" %}
**💡 提示**: 如果射线投射结果的处理需要大量计算（比如运行寻路算法），你可能希望在异步函数中执行该计算。
{% endhint %}

## await 语句

一个 `await` 该语句会强制执行在继续到下一行代码之前先等待响应。 `await` 语句只能在异步代码块中使用。

```ts
// 声明函数
async function myAsyncTask() {
	try {
		let response = await fetch(callUrl)
		let json = await response.json()
		console.log(json)
	} catch {
		console.log('无法访问该 URL')
	}
}

// 调用函数
myAsyncTask()

// 其余代码继续执行
```

上面的示例执行了一个包含 `fetch()` 从外部 API 获取数据的操作的函数。 `fetch()` 该操作是异步的，因为我们无法预测服务器需要多长时间才能响应。不过，在将其解析为 json 之前，下一行需要先获得该操作的输出。这里的 `await` 语句确保只有在该操作返回值之后，下一行才会运行。同样地， `response.json()` 函数也是异步的，但下一行需要先完成 json 解析才能打印它。第二个 `await` 语句会强制下一行只在 json 解析完成后才被调用，无论这需要多长时间。

## 为函数调用设置超时

使用 `setTimeout` 用于在某些代码行运行前等待一段时间。这需要两个参数：

* 要执行的函数
* 在执行该函数前要等待的毫秒数

下面的示例会等待 1000 毫秒（等于 1 秒），然后执行一个向控制台记录消息的简单函数。

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

console.log('这会立即打印出来')

timers.setTimeout(() => {
	// 延迟后执行的函数
    console.log('这会在 1 秒后打印出来')
}, 1000)
```

该 `clearTimeout` 可用于取消一个 `setTimeout` 仍在等待执行的函数。 `setTimeout` 会返回一个定时器 id（一个数字），然后你可以将其传递给 `clearTimeout`。在这种情况下，变量 `timeoutId` 是在执行 `setTimeout`时获得的，然后将其传递给 `clearTimeout` 以取消它。

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

const timeoutId = timers.setTimeout(() => {
    console.log('等待 1 秒后再执行这个函数')
}, 1000)

timers.clearTimeout(timeoutId)
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/bian-cheng-mo-shi/async-functions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
