关于 unity-unitask-design
面向使用 UniTask 2.5.10 的 Unity 开发者的异步编程参考模块,覆盖时序、取消、组合和 Unity 异步操作转换。规则附有源码位置,便于编写或审查代码时验证行为。
主要功能
- 01说明 UniTask 与异步方法规则
- 02整理 PlayerLoopTiming 与延迟行为
- 03涵盖 CancellationToken 处理
- 04介绍 WhenAll、WhenAny 等组合方式
- 05列出 Unity 异步操作转换规则
适用场景
- 01编写或审查 UniTask 异步方法
- 02选择 PlayerLoopTiming 并处理取消
- 03组合多个异步操作
- 04将 Unity 异步操作转换为 UniTask
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ besty0728/ unity-skills --skill unity-unitask-design安装后在 Claude Code 中输入/unity-unitask-design确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
ASYNCENUMERABLE.mdBASICS.mdCANCELLATION.mdCOMPOSITION.mdCONVERSION.mdPITFALLS.mdPLAYERLOOP.mdTRIGGERS.md详细介绍
**调用本模块中的任何技能前:**如果你打算根据技能名称或描述猜测参数后调用技能,请先停下——先阅读此文件(或通过
GET /skills/recommend?includeSchema=true获取其架构)。如果你已从 recommend/schema 获取参数定义,则可直接进行 dryRun。
触发条件
- 编写或审查 async UniTask 代码
- 选择 PlayerLoopTiming
- 处理 CancellationToken
- 组合 WhenAll/WhenAny
- 编写或审查 async UniTask 代码、选择 PlayerLoopTiming、处理 CancellationToken、组合 WhenAll/WhenAny
UniTask - 设计规则
参考模块。每条规则均源自 Cysharp UniTask,并附有具体文件和行号,出处可供核查:
- 2.5.10 —
[email protected](Unity 2018.4 基准版本;目前也用于 2022.3 / Unity 6)
模式:仅供文档参考——无 REST 技能需要设置门禁;任何运行模式(Approval / Auto / Bypass)下均可自由加载。
何时加载此模块
在编写或审查以下任何内容前加载:
- 任何
async UniTask/async UniTask<T>/async UniTaskVoid方法签名 .Forget()、.AttachExternalCancellation(token)、.SuppressCancellationThrow()链式调用UniTask.Yield、UniTask.NextFrame、UniTask.Delay、UniTask.WaitForEndOfFrame、UniTask.WaitForFixedUpdateUniTask.WaitUntil、UniTask.WaitWhile、UniTask.WaitUntilValueChanged、UniTask.WaitUntilCanceledUniTask.WhenAll、UniTask.WhenAny、UniTask.WhenEachUniTask.SwitchToMainThread、UniTask.SwitchToThreadPool、UniTask.RunAsyncOperation.ToUniTask()、UnityWebRequest.SendWebRequest().ToUniTask()、Coroutine.ToUniTask()this.GetCancellationTokenOnDestroy()、GetAsyncStartTrigger()及其他AsyncTrigger*扩展方法UniTaskCompletionSource/UniTaskCompletionSource<T>手动完成源IUniTaskAsyncEnumerable<T>/UniTaskAsyncEnumerable/AsyncReactiveProperty<T>/Channel<T>- 禁止使用
Task.Run/SwitchToThreadPool的 WebGL 特定异步代码路径
关键规则摘要
| # | 规则 | 源代码位置 |
|---|---|---|
| 1 | UniTask 是一个 readonly partial struct(值类型)。等待一次后,其 IUniTaskSource 就会被回收;对同一个 UniTask 变量等待两次会抛出异常。使用 .Preserve() 获取可多次等待的记忆化副本。 | UniTask.cs:34, UniTask.cs:103-113 |
| 2 | 方法返回的 UniTask 必须 await、调用 .Forget(),或调用 .AttachExternalCancellation(token)。未处理的 UniTask 会将异常静默地传递到 UniTaskScheduler.UnobservedTaskException。 | UniTaskScheduler.cs:13, UniTaskVoid.cs:11-17 |
| 3 | PlayerLoopTiming 定义了 16 个时序槽(2020.2+;较早的 Unity 版本中为 14 个)。默认的 UniTask.Yield() / UniTask.Delay 使用 PlayerLoopTiming.Update。将 LastPostLateUpdate 与旧版 WaitForEndOfFrame 协程混用,会改变观察到的帧顺序。 | PlayerLoopHelper.cs:71-99 |
| 4 | UniTask.Delay(int ms, DelayType, PlayerLoopTiming, CancellationToken, bool cancelImmediately) 接受 DelayType.DeltaTime / UnscaledDeltaTime / Realtime。旧的 bool ignoreTimeScale 重载仍然存在,但会混用不同语义——新代码优先使用 DelayType 重载。 | UniTask.Delay.cs:12-20, UniTask.Delay.cs:147-165 |
| 5 | this.GetCancellationTokenOnDestroy() 在 AsyncTriggerExtensions 中为 MonoBehaviour、GameObject 和 Component 定义。普通 C# 类不会获得此扩展——必须显式持有自己的 CancellationTokenSource。 | Triggers/AsyncTriggerExtensions.cs:14,22,28 |
| 6 | UniTask.WhenAll(params UniTask[] tasks) 和 IEnumerable<UniTask> 重载都存在。语义上与 Task.WhenAll 一致,但当任务原生使用 UniTask 时不会产生分配。WhenAny 对 UniTask<T> 返回 (winnerIndex, result) 元组。 | UniTask.WhenAll.cs:12,22,31,41, UniTask.WhenAny.cs |
| 7 | AsyncOperation.ToUniTask(IProgress<float>, PlayerLoopTiming, CancellationToken) 是标准适配器。await operation 也可用,但如果同时设置 operation.completed += …,进度回调会在不提示的情况下泄漏。 | UnityAsyncExtensions.cs |
| 8 | UniTaskCompletionSource 和 UniTaskCompletionSource<T> 支持 TrySetResult / TrySetException / TrySetCanceled。这三种方法中的任何一种成功后,后续调用都会返回 false——不会抛出异常。 | UniTaskCompletionSource.cs:573,610,754,792 |
| 9 | UniTask.SwitchToThreadPool() 和 UniTask.Run(...) 在所有平台上编译时都可用,但在 WebGL 上运行时会抛出 NotSupportedException。请使用 `#if !UNITY_WEBGL | |
| 10 | 返回 async UniTaskVoid 是即发即弃的惯用写法,可在方法内部使用 await。async void 方法无法返回 UniTask——这是从 Task 迁移时常见的编译错误。 | UniTaskVoid.cs:11-17, UniTask.Factory.cs:112-131 |
子文档路由
| 子文档 | 何时阅读 |
|---|---|
| BASICS.md | UniTask 与 Task 的差异、结构体语义、UniTaskVoid、零分配状态机、AsyncUniTaskMethodBuilder |
| PLAYERLOOP.md | 16 种 PlayerLoopTiming 的表格、Yield/NextFrame/Delay/WaitForEndOfFrame/WaitForFixedUpdate、DelayType、与旧版协程的帧顺序 |
| CANCELLATION.md | CancellationToken 模式、GetCancellationTokenOnDestroy(3 个重载)、AttachExternalCancellation、CancelAfterSlim、AddTo、OperationCanceledException 流程 |
| COMPOSITION.md | WhenAll、WhenAny、WhenEach、Forget、SuppressCancellationThrow、ContinueWith、超时模式 |
| CONVERSION.md | AsyncOperation.ToUniTask、UnityWebRequest.SendWebRequest().ToUniTask、IEnumerator.ToUniTask、Task.AsUniTask、UniTask.AsTask、UniTask.ToCoroutine |
| ASYNCENUMERABLE.md | IUniTaskAsyncEnumerable<T>、UniTaskAsyncEnumerable、AsyncReactiveProperty<T>、Channel<T>、EveryValueChanged、Publish、异步 LINQ 运算符 |
| TRIGGERS.md | AsyncTriggerBase、GetAsyncStartTrigger、GetAsyncDestroyTrigger、OnCollisionEnterAsync、OnClickAsync、MonoBehaviourMessagesTriggers、生命周期取消 |
| PITFALLS.md | 30 个具体的幻觉 / 运行时陷阱(重复 await、忘记调用 Forget、WebGL 线程池、跟踪器内存、错误的 PlayerLoopTiming、协程互操作错误) |
路由到其他模块
- 在架构层面选择
UniTask、原生Task和IEnumerator→ 加载 async - DOTween 补间动画 → UniTask 适配器(
tween.ToUniTask(TweenCancelBehaviour, token))→ 加载 dotween-design - YooAsset 句柄 → 通过
handle.ToUniTask()扩展转换为 UniTask → 加载 yooasset-design - Addressables
AsyncOperationHandle.ToUniTask()规则 → 加载 addressables-design - 审查大量使用 UniTask 的代码路径的性能(跟踪器开销、状态机分配)→ 加载 performance
- UniTask 使用者的 Asmdef 布局(
Cysharp.Threading.Tasks.asmdef引用)→ 加载 asmdef
版本范围
目标版本为 UniTask 2.5.10。较早的 2.x 版本大多与源码兼容;主要差异:
WaitForEndOfFrame(MonoBehaviour coroutineRunner)重载是在较新的 2.x 中添加的——在 2023.1+ 中可使用无参数重载(#if UNITY_2023_1_OR_NEWER)。参见UniTask.Delay.cs:78-103。UniTask.WhenEach是较新的新增功能;并非所有 2.x 构建版本都包含它。
不确定时,请查阅引用的源码,而不是依赖记忆。
评论
支持 Markdown