{"id":21358883,"url":"https://github.com/gameframex/com.gameframex.unity.cysharp.unitask","last_synced_at":"2025-10-08T05:54:08.188Z","repository":{"id":210389110,"uuid":"726434924","full_name":"GameFrameX/com.gameframex.unity.cysharp.unitask","owner":"GameFrameX","description":"从com.cysharp.unitask 二次分发而来","archived":false,"fork":false,"pushed_at":"2025-06-01T06:03:50.000Z","size":330,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-13T00:43:00.474Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GameFrameX.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-12-02T11:45:51.000Z","updated_at":"2025-06-01T06:03:53.000Z","dependencies_parsed_at":"2024-04-12T12:09:41.130Z","dependency_job_id":"ff1ba2c5-5334-40b4-8ac7-a6a227e33c84","html_url":"https://github.com/GameFrameX/com.gameframex.unity.cysharp.unitask","commit_stats":null,"previous_names":["alianblank/com.cysharp.unitask","alianblank/com.alianblank.gameframex.unity.cysharp.unitask","gameframex/com.gameframex.unity.cysharp.unitask"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/GameFrameX/com.gameframex.unity.cysharp.unitask","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameFrameX%2Fcom.gameframex.unity.cysharp.unitask","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameFrameX%2Fcom.gameframex.unity.cysharp.unitask/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameFrameX%2Fcom.gameframex.unity.cysharp.unitask/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameFrameX%2Fcom.gameframex.unity.cysharp.unitask/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GameFrameX","download_url":"https://codeload.github.com/GameFrameX/com.gameframex.unity.cysharp.unitask/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GameFrameX%2Fcom.gameframex.unity.cysharp.unitask/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278897285,"owners_count":26064780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-22T05:22:45.434Z","updated_at":"2025-10-08T05:54:08.165Z","avatar_url":"https://github.com/GameFrameX.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 基于`UniTask` 的二次修改\r\n\r\n该库主要服务于 `https://github.com/AlianBlank/GameFrameX` 作为子库使用。\r\n\r\n\r\n# 使用方式(三种方式)\r\n1. 直接在 `manifest.json` 文件中添加以下内容\r\n   ```json\r\n      {\"com.gameframex.unity.cysharp.unitask\": \"https://github.com/AlianBlank/com.gameframex.unity.cysharp.unitask.git\"}\r\n    ```\r\n2. 在Unity 的`Packages Manager` 中使用`Git URL` 的方式添加库,地址为：https://github.com/AlianBlank/com.gameframex.unity.cysharp.unitask.git\r\n\r\n3. 直接下载仓库放置到Unity 项目的`Packages` 目录下。会自动加载识别\r\n\r\n# 改动功能\r\n\r\n1. 增加 `link.xml` 的裁剪过滤\r\n2. 增加对`Packages` 的支持\r\n3. 增加延迟一帧的接口\r\n\r\n\r\n# 同步版本\r\nhttps://github.com/Cysharp/UniTask/commit/5cc97c7f0085624b6ef57853d70b404440060cef\r\n\r\n------------------------------------------------------------------------------------------------------------------\r\n\r\nUniTask\r\n===\r\n[![GitHub Actions](https://github.com/Cysharp/UniTask/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/UniTask/actions) [![Releases](https://img.shields.io/github/release/Cysharp/UniTask.svg)](https://github.com/Cysharp/UniTask/releases) [![Readme_CN](https://img.shields.io/badge/UniTask-%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3-red)](https://github.com/Cysharp/UniTask/blob/master/README_CN.md)\r\n\r\nProvides an efficient allocation free async/await integration for Unity.\r\n\r\n* Struct based `UniTask\u003cT\u003e` and custom AsyncMethodBuilder to achieve zero allocation\r\n* Makes all Unity AsyncOperations and Coroutines awaitable\r\n* PlayerLoop based task(`UniTask.Yield`, `UniTask.Delay`, `UniTask.DelayFrame`, etc..) that enable replacing all coroutine operations\r\n* MonoBehaviour Message Events and uGUI Events as awaitable/async-enumerable\r\n* Runs completely on Unity's PlayerLoop so doesn't use threads and runs on WebGL, wasm, etc.\r\n* Asynchronous LINQ, with Channel and AsyncReactiveProperty\r\n* TaskTracker window to prevent memory leaks\r\n* Highly compatible behaviour with Task/ValueTask/IValueTaskSource\r\n\r\nFor technical details, see blog post: [UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ\r\n](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)  \r\nFor advanced tips, see blog post: [Extends UnityWebRequest via async decorator pattern — Advanced Techniques of UniTask](https://medium.com/@neuecc/extends-unitywebrequest-via-async-decorator-pattern-advanced-techniques-of-unitask-ceff9c5ee846)\r\n\r\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\r\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\r\n## Table of Contents\r\n\r\n- [Getting started](#getting-started)\r\n- [Basics of UniTask and AsyncOperation](#basics-of-unitask-and-asyncoperation)\r\n- [Cancellation and Exception handling](#cancellation-and-exception-handling)\r\n- [Timeout handling](#timeout-handling)\r\n- [Progress](#progress)\r\n- [PlayerLoop](#playerloop)\r\n- [async void vs async UniTaskVoid](#async-void-vs-async-unitaskvoid)\r\n- [UniTaskTracker](#unitasktracker)\r\n- [External Assets](#external-assets)\r\n- [AsyncEnumerable and Async LINQ](#asyncenumerable-and-async-linq)\r\n- [Awaitable Events](#awaitable-events)\r\n- [Channel](#channel)\r\n- [For Unit Testing](#for-unit-testing)\r\n- [ThreadPool limitation](#threadpool-limitation)\r\n- [IEnumerator.ToUniTask limitation](#ienumeratortounitask-limitation)\r\n- [For UnityEditor](#for-unityeditor)\r\n- [Compare with Standard Task API](#compare-with-standard-task-api)\r\n- [Pooling Configuration](#pooling-configuration)\r\n- [Allocation on Profiler](#allocation-on-profiler)\r\n- [UniTaskSynchronizationContext](#unitasksynchronizationcontext)\r\n- [API References](#api-references)\r\n- [UPM Package](#upm-package)\r\n  - [Install via git URL](#install-via-git-url)\r\n  - [Install via OpenUPM](#install-via-openupm)\r\n- [.NET Core](#net-core)\r\n- [License](#license)\r\n\r\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\r\n\r\nGetting started\r\n---\r\nInstall via [UPM package](#upm-package) or asset package(`UniTask.*.*.*.unitypackage`) available in [UniTask/releases](https://github.com/Cysharp/UniTask/releases) page.\r\n\r\n```csharp\r\n// extension awaiter/methods can be used by this namespace\r\nusing Cysharp.Threading.Tasks;\r\n\r\n// You can return type as struct UniTask\u003cT\u003e(or UniTask), it is unity specialized lightweight alternative of Task\u003cT\u003e\r\n// zero allocation and fast excution for zero overhead async/await integrate with Unity\r\nasync UniTask\u003cstring\u003e DemoAsync()\r\n{\r\n    // You can await Unity's AsyncObject\r\n    var asset = await Resources.LoadAsync\u003cTextAsset\u003e(\"foo\");\r\n    var txt = (await UnityWebRequest.Get(\"https://...\").SendWebRequest()).downloadHandler.text;\r\n    await SceneManager.LoadSceneAsync(\"scene2\");\r\n\r\n    // .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject\r\n    var asset2 = await Resources.LoadAsync\u003cTextAsset\u003e(\"bar\").WithCancellation(this.GetCancellationTokenOnDestroy());\r\n\r\n    // .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress\u003cT\u003e\r\n    var asset3 = await Resources.LoadAsync\u003cTextAsset\u003e(\"baz\").ToUniTask(Progress.Create\u003cfloat\u003e(x =\u003e Debug.Log(x)));\r\n\r\n    // await frame-based operation like a coroutine\r\n    await UniTask.DelayFrame(100); \r\n\r\n    // replacement of yield return new WaitForSeconds/WaitForSecondsRealtime\r\n    await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false);\r\n    \r\n    // yield any playerloop timing(PreUpdate, Update, LateUpdate, etc...)\r\n    await UniTask.Yield(PlayerLoopTiming.PreLateUpdate);\r\n\r\n    // replacement of yield return null\r\n    await UniTask.Yield();\r\n    await UniTask.NextFrame();\r\n\r\n    // replacement of WaitForEndOfFrame(requires MonoBehaviour(CoroutineRunner))\r\n    await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour\r\n\r\n    // replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))\r\n    await UniTask.WaitForFixedUpdate();\r\n    \r\n    // replacement of yield return WaitUntil\r\n    await UniTask.WaitUntil(() =\u003e isActive == false);\r\n\r\n    // special helper of WaitUntil\r\n    await UniTask.WaitUntilValueChanged(this, x =\u003e x.isActive);\r\n\r\n    // You can await IEnumerator coroutines\r\n    await FooCoroutineEnumerator();\r\n\r\n    // You can await a standard task\r\n    await Task.Run(() =\u003e 100);\r\n\r\n    // Multithreading, run on ThreadPool under this code\r\n    await UniTask.SwitchToThreadPool();\r\n\r\n    /* work on ThreadPool */\r\n\r\n    // return to MainThread(same as `ObserveOnMainThread` in UniRx)\r\n    await UniTask.SwitchToMainThread();\r\n\r\n    // get async webrequest\r\n    async UniTask\u003cstring\u003e GetTextAsync(UnityWebRequest req)\r\n    {\r\n        var op = await req.SendWebRequest();\r\n        return op.downloadHandler.text;\r\n    }\r\n\r\n    var task1 = GetTextAsync(UnityWebRequest.Get(\"http://google.com\"));\r\n    var task2 = GetTextAsync(UnityWebRequest.Get(\"http://bing.com\"));\r\n    var task3 = GetTextAsync(UnityWebRequest.Get(\"http://yahoo.com\"));\r\n\r\n    // concurrent async-wait and get results easily by tuple syntax\r\n    var (google, bing, yahoo) = await UniTask.WhenAll(task1, task2, task3);\r\n\r\n    // shorthand of WhenAll, tuple can await directly\r\n    var (google2, bing2, yahoo2) = await (task1, task2, task3);\r\n\r\n    // return async-value.(or you can use `UniTask`(no result), `UniTaskVoid`(fire and forget)).\r\n    return (asset as TextAsset)?.text ?? throw new InvalidOperationException(\"Asset not found\");\r\n}\r\n```\r\n\r\nBasics of UniTask and AsyncOperation\r\n---\r\nUniTask features rely on C# 7.0([task-like custom async method builder feature](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md)) so the required Unity version is after `Unity 2018.3`, the official lowest version supported is `Unity 2018.4.13f1`.\r\n\r\nWhy is UniTask(custom task-like object) required? Because Task is too heavy and not matched to Unity threading (single-thread). UniTask does not use threads and SynchronizationContext/ExecutionContext because Unity's asynchronous object is automaticaly dispatched by Unity's engine layer. It achieves faster and lower allocation, and is completely integrated with Unity.\r\n\r\nYou can await `AsyncOperation`, `ResourceRequest`, `AssetBundleRequest`, `AssetBundleCreateRequest`, `UnityWebRequestAsyncOperation`, `AsyncGPUReadbackRequest`, `IEnumerator` and others when `using Cysharp.Threading.Tasks;`.\r\n\r\nUniTask provides three pattern of extension methods.\r\n\r\n```csharp\r\n* await asyncOperation;\r\n* .WithCancellation(CancellationToken);\r\n* .ToUniTask(IProgress, PlayerLoopTiming, CancellationToken);\r\n```\r\n\r\n`WithCancellation` is a simple version of `ToUniTask`, both return `UniTask`. For details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section.\r\n\r\n\u003e Note: await directly is returned from native timing of PlayerLoop but WithCancellation and ToUniTask are returned from specified PlayerLoopTiming. For details of timing, see: [PlayerLoop](#playerloop) section.\r\n\r\n\u003e Note: AssetBundleRequest has `asset` and `allAssets`, default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.\r\n\r\nThe type of `UniTask` can use utilities like `UniTask.WhenAll`, `UniTask.WhenAny`. They are like `Task.WhenAll`/`Task.WhenAny` but the return type is more useful. They return value tuples so you can deconstruct each result and pass multiple types.\r\n\r\n```csharp\r\npublic async UniTaskVoid LoadManyAsync()\r\n{\r\n    // parallel load.\r\n    var (a, b, c) = await UniTask.WhenAll(\r\n        LoadAsSprite(\"foo\"),\r\n        LoadAsSprite(\"bar\"),\r\n        LoadAsSprite(\"baz\"));\r\n}\r\n\r\nasync UniTask\u003cSprite\u003e LoadAsSprite(string path)\r\n{\r\n    var resource = await Resources.LoadAsync\u003cSprite\u003e(path);\r\n    return (resource as Sprite);\r\n}\r\n```\r\n\r\nIf you want to convert a callback to UniTask, you can use `UniTaskCompletionSource\u003cT\u003e` which is a lightweight edition of `TaskCompletionSource\u003cT\u003e`. \r\n\r\n```csharp\r\npublic UniTask\u003cint\u003e WrapByUniTaskCompletionSource()\r\n{\r\n    var utcs = new UniTaskCompletionSource\u003cint\u003e();\r\n\r\n    // when complete, call utcs.TrySetResult();\r\n    // when failed, call utcs.TrySetException();\r\n    // when cancel, call utcs.TrySetCanceled();\r\n\r\n    return utcs.Task; //return UniTask\u003cint\u003e\r\n}\r\n```\r\n\r\nYou can convert Task -\u003e UniTask: `AsUniTask`, `UniTask` -\u003e `UniTask\u003cAsyncUnit\u003e`: `AsAsyncUnitUniTask`, `UniTask\u003cT\u003e` -\u003e `UniTask`: `AsUniTask`. `UniTask\u003cT\u003e` -\u003e `UniTask`'s conversion cost is free.\r\n\r\nIf you want to convert async to coroutine, you can use `.ToCoroutine()`, this is useful if you want to only allow using the coroutine system.\r\n\r\nUniTask can not await twice. This is a similar constraint to the [ValueTask/IValueTaskSource](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=netcore-3.1) introduced in .NET Standard 2.1.\r\n\r\n\u003e The following operations should never be performed on a ValueTask\u003cTResult\u003e instance:\r\n\u003e\r\n\u003e * Awaiting the instance multiple times.\r\n\u003e * Calling AsTask multiple times.\r\n\u003e * Using .Result or .GetAwaiter().GetResult() when the operation hasn't yet completed, or using them multiple times.\r\n\u003e * Using more than one of these techniques to consume the instance.\r\n\u003e\r\n\u003e If you do any of the above, the results are undefined.\r\n\r\n```csharp\r\nvar task = UniTask.DelayFrame(10);\r\nawait task;\r\nawait task; // NG, throws Exception\r\n```\r\n\r\nStore to the class field, you can use `UniTask.Lazy` that supports calling multiple times. `.Preserve()` allows for multiple calls (internally cached results). This is useful when there are multiple calls in a function scope.\r\n\r\nAlso `UniTaskCompletionSource` can await multiple times and await from many callers.\r\n\r\nCancellation and Exception handling\r\n---\r\nSome UniTask factory methods have a `CancellationToken cancellationToken = default` parameter. Also some async operations for Unity have `WithCancellation(CancellationToken)` and `ToUniTask(..., CancellationToken cancellation = default)` extension methods. \r\n\r\nYou can pass `CancellationToken` to parameter by standard [`CancellationTokenSource`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource).\r\n\r\n```csharp\r\nvar cts = new CancellationTokenSource();\r\n\r\ncancelButton.onClick.AddListener(() =\u003e\r\n{\r\n    cts.Cancel();\r\n});\r\n\r\nawait UnityWebRequest.Get(\"http://google.co.jp\").SendWebRequest().WithCancellation(cts.Token);\r\n\r\nawait UniTask.DelayFrame(1000, cancellationToken: cts.Token);\r\n```\r\n\r\nCancellationToken can be created by `CancellationTokenSource` or MonoBehaviour's extension method `GetCancellationTokenOnDestroy`.\r\n\r\n```csharp\r\n// this CancellationToken lifecycle is same as GameObject.\r\nawait UniTask.DelayFrame(1000, cancellationToken: this.GetCancellationTokenOnDestroy());\r\n```\r\n\r\nFor propagate Cancellation, all async method recommend to accept `CancellationToken cancellationToken` at last argument, and pass `CancellationToken` from root to end.\r\n\r\n```csharp\r\nawait FooAsync(this.GetCancellationTokenOnDestroy());\r\n\r\n// ---\r\n\r\nasync UniTask FooAsync(CancellationToken cancellationToken)\r\n{\r\n    await BarAsync(cancellationToken);\r\n}\r\n\r\nasync UniTask BarAsync(CancellationToken cancellationToken)\r\n{\r\n    await UniTask.Delay(TimeSpan.FromSeconds(3), cancellationToken);\r\n}\r\n```\r\n\r\n`CancellationToken` means lifecycle of async. You can hold your own lifecycle insteadof default CancellationTokenOnDestroy.\r\n\r\n```csharp\r\npublic class MyBehaviour : MonoBehaviour\r\n{\r\n    CancellationTokenSource disableCancellation = new CancellationTokenSource();\r\n    CancellationTokenSource destroyCancellation = new CancellationTokenSource();\r\n\r\n    private void OnEnable()\r\n    {\r\n        if (disableCancellation != null)\r\n        {\r\n            disableCancellation.Dispose();\r\n        }\r\n        disableCancellation = new CancellationTokenSource();\r\n    }\r\n\r\n    private void OnDisable()\r\n    {\r\n        disableCancellation.Cancel();\r\n    }\r\n\r\n    private void OnDestroy()\r\n    {\r\n        destroyCancellation.Cancel();\r\n        destroyCancellation.Dispose();\r\n    }\r\n}\r\n```\r\n\r\nWhen cancellation is detected, all methods throw `OperationCanceledException` and propagate upstream. When exception(not limited to `OperationCanceledException`) is not handled in async method, it is propagated finally to `UniTaskScheduler.UnobservedTaskException`. The default behaviour of received unhandled exception is to write log as exception. Log level can be changed using `UniTaskScheduler.UnobservedExceptionWriteLogType`. If you want to use custom behaviour, set an action to `UniTaskScheduler.UnobservedTaskException.`\r\n\r\nAndalso `OperationCanceledException` is a special exception, this is silently ignored at `UnobservedTaskException`.\r\n\r\nIf you want to cancel behaviour in an async UniTask method, throw `OperationCanceledException` manually.\r\n\r\n```csharp\r\npublic async UniTask\u003cint\u003e FooAsync()\r\n{\r\n    await UniTask.Yield();\r\n    throw new OperationCanceledException();\r\n}\r\n```\r\n\r\nIf you handle an exception but want to ignore(propagate to global cancellation handling), use an exception filter.\r\n\r\n```csharp\r\npublic async UniTask\u003cint\u003e BarAsync()\r\n{\r\n    try\r\n    {\r\n        var x = await FooAsync();\r\n        return x * 2;\r\n    }\r\n    catch (Exception ex) when (!(ex is OperationCanceledException)) // when (ex is not OperationCanceledException) at C# 9.0\r\n    {\r\n        return -1;\r\n    }\r\n}\r\n```\r\n\r\nthrows/catch `OperationCanceledException` is slightly heavy, so if performance is a concern, use `UniTask.SuppressCancellationThrow` to avoid OperationCanceledException throw. It returns `(bool IsCanceled, T Result)` instead of throwing.\r\n\r\n```csharp\r\nvar (isCanceled, _) = await UniTask.DelayFrame(10, cancellationToken: cts.Token).SuppressCancellationThrow();\r\nif (isCanceled)\r\n{\r\n    // ...\r\n}\r\n```\r\n\r\nNote: Only suppress throws if you call directly into the most source method. Otherwise, the return value will be converted, but the entire pipeline will not suppress throws.\r\n\r\nTimeout handling\r\n---\r\nTimeout is a variation of cancellation. You can set timeout by `CancellationTokenSouce.CancelAfterSlim(TimeSpan)` and pass CancellationToken to async methods.\r\n\r\n```csharp\r\nvar cts = new CancellationTokenSource();\r\ncts.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.\r\n\r\ntry\r\n{\r\n    await UnityWebRequest.Get(\"http://foo\").SendWebRequest().WithCancellation(cts.Token);\r\n}\r\ncatch (OperationCanceledException ex)\r\n{\r\n    if (ex.CancellationToken == cts.Token)\r\n    {\r\n        UnityEngine.Debug.Log(\"Timeout\");\r\n    }\r\n}\r\n```\r\n\r\n\u003e `CancellationTokenSouce.CancelAfter` is a standard api. However in Unity you should not use it because it depends threading timer. `CancelAfterSlim` is UniTask's extension methods, it uses PlayerLoop instead.\r\n\r\nIf you want to use timeout with other source of cancellation, use `CancellationTokenSource.CreateLinkedTokenSource`.\r\n\r\n```csharp\r\nvar cancelToken = new CancellationTokenSource();\r\ncancelButton.onClick.AddListener(()=\u003e\r\n{\r\n    cancelToken.Cancel(); // cancel from button click.\r\n});\r\n\r\nvar timeoutToken = new CancellationTokenSource();\r\ntimeoutToken.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.\r\n\r\ntry\r\n{\r\n    // combine token\r\n    var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, timeoutToken.Token);\r\n\r\n    await UnityWebRequest.Get(\"http://foo\").SendWebRequest().WithCancellation(linkedTokenSource.Token);\r\n}\r\ncatch (OperationCanceledException ex)\r\n{\r\n    if (timeoutToken.IsCancellationRequested)\r\n    {\r\n        UnityEngine.Debug.Log(\"Timeout.\");\r\n    }\r\n    else if (cancelToken.IsCancellationRequested)\r\n    {\r\n        UnityEngine.Debug.Log(\"Cancel clicked.\");\r\n    }\r\n}\r\n```\r\n\r\nOptimize for reduce allocation of CancellationTokenSource for timeout per call async method, you can use UniTask's `TimeoutController`.\r\n\r\n```csharp\r\nTimeoutController timeoutController = new TimeoutController(); // setup to field for reuse.\r\n\r\nasync UniTask FooAsync()\r\n{\r\n    try\r\n    {\r\n        // you can pass timeoutController.Timeout(TimeSpan) to cancellationToken.\r\n        await UnityWebRequest.Get(\"http://foo\").SendWebRequest()\r\n            .WithCancellation(timeoutController.Timeout(TimeSpan.FromSeconds(5)));\r\n        timeoutController.Reset(); // call Reset(Stop timeout timer and ready for reuse) when succeed.\r\n    }\r\n    catch (OperationCanceledException ex)\r\n    {\r\n        if (timeoutController.IsTimeout())\r\n        {\r\n            UnityEngine.Debug.Log(\"timeout\");\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nIf you want to use timeout with other source of cancellation, use `new TimeoutController(CancellationToken)`.\r\n\r\n```csharp\r\nTimeoutController timeoutController;\r\nCancellationTokenSource clickCancelSource;\r\n\r\nvoid Start()\r\n{\r\n    this.clickCancelSource = new CancellationTokenSource();\r\n    this.timeoutController = new TimeoutController(clickCancelSource);\r\n}\r\n```\r\n\r\nNote: UniTask has `.Timeout`, `.TimeoutWithoutException` methods however, if possible, do not use these, please pass `CancellationToken`. Because `.Timeout` work from external of task, can not stop timeoutted task. `.Timeout` means ignore result when timeout. If you pass a `CancellationToken` to the method, it will act from inside of the task, so it is possible to stop a running task.\r\n\r\nProgress\r\n---\r\nSome async operations for unity have `ToUniTask(IProgress\u003cfloat\u003e progress = null, ...)` extension methods. \r\n\r\n```csharp\r\nvar progress = Progress.Create\u003cfloat\u003e(x =\u003e Debug.Log(x));\r\n\r\nvar request = await UnityWebRequest.Get(\"http://google.co.jp\")\r\n    .SendWebRequest()\r\n    .ToUniTask(progress: progress);\r\n```\r\n\r\nYou should not use standard `new System.Progress\u003cT\u003e`, because it causes allocation every time. Use `Cysharp.Threading.Tasks.Progress` instead. This progress factory has two methods, `Create` and `CreateOnlyValueChanged`. `CreateOnlyValueChanged` calls only when the progress value has changed.\r\n\r\nImplementing IProgress interface to caller is better as there is no lambda allocation.\r\n\r\n```csharp\r\npublic class Foo : MonoBehaviour, IProgress\u003cfloat\u003e\r\n{\r\n    public void Report(float value)\r\n    {\r\n        UnityEngine.Debug.Log(value);\r\n    }\r\n\r\n    public async UniTaskVoid WebRequest()\r\n    {\r\n        var request = await UnityWebRequest.Get(\"http://google.co.jp\")\r\n            .SendWebRequest()\r\n            .ToUniTask(progress: this); // pass this\r\n    }\r\n}\r\n```\r\n\r\nPlayerLoop\r\n---\r\nUniTask is run on a custom [PlayerLoop](https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.html). UniTask's playerloop based methods (such as `Delay`, `DelayFrame`, `asyncOperation.ToUniTask`, etc...) accept this `PlayerLoopTiming`.\r\n\r\n```csharp\r\npublic enum PlayerLoopTiming\r\n{\r\n    Initialization = 0,\r\n    LastInitialization = 1,\r\n\r\n    EarlyUpdate = 2,\r\n    LastEarlyUpdate = 3,\r\n\r\n    FixedUpdate = 4,\r\n    LastFixedUpdate = 5,\r\n\r\n    PreUpdate = 6,\r\n    LastPreUpdate = 7,\r\n\r\n    Update = 8,\r\n    LastUpdate = 9,\r\n\r\n    PreLateUpdate = 10,\r\n    LastPreLateUpdate = 11,\r\n\r\n    PostLateUpdate = 12,\r\n    LastPostLateUpdate = 13\r\n    \r\n#if UNITY_2020_2_OR_NEWER\r\n    TimeUpdate = 14,\r\n    LastTimeUpdate = 15,\r\n#endif\r\n}\r\n```\r\n\r\nIt indicates when to run, you can check [PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae) to Unity's default playerloop and injected UniTask's custom loop.\r\n\r\n`PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`.\r\n\r\n\u003e `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`.\r\n\r\n`yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`.\r\n\r\n\u003e UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and runs on YieldRunner. It is the most lightweight and fastest.\r\n\r\n`AsyncOperation` is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after being called, the loaded scene's `Start` is called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.\r\n\r\nIn UniTask, await directly uses native timing, while `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.\r\n\r\nIn the stacktrace, you can check where it is running in playerloop.\r\n\r\n![image](https://user-images.githubusercontent.com/46207/83735571-83caea80-a68b-11ea-8d22-5e22864f0d24.png)\r\n\r\nBy default, UniTask's PlayerLoop is initialized at `[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]`.\r\n\r\nThe order in which methods are called in BeforeSceneLoad is nondeterministic, so if you want to use UniTask in other BeforeSceneLoad methods, you should try to initialize it before this.\r\n\r\n```csharp\r\n// AfterAssembliesLoaded is called before BeforeSceneLoad\r\n[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]\r\npublic static void InitUniTaskLoop()\r\n{\r\n    var loop = PlayerLoop.GetCurrentPlayerLoop();\r\n    Cysharp.Threading.Tasks.PlayerLoopHelper.Initialize(ref loop);\r\n}\r\n```\r\n\r\nIf you import Unity's `Entities` package, that resets the custom player loop to default at `BeforeSceneLoad` and injects ECS's loop. When Unity calls ECS's inject method after UniTask's initialize method, UniTask will no longer work.\r\n\r\nTo solve this issue, you can re-initialize the UniTask PlayerLoop after ECS is initialized.\r\n\r\n```csharp\r\n// Get ECS Loop.\r\nvar playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;\r\n\r\n// Setup UniTask's PlayerLoop.\r\nPlayerLoopHelper.Initialize(ref playerLoop);\r\n```\r\n\r\nYou can diagnose whether UniTask's player loop is ready by calling `PlayerLoopHelper.IsInjectedUniTaskPlayerLoop()`. And also `PlayerLoopHelper.DumpCurrentPlayerLoop` logs all current playerloops to console.\r\n\r\n```csharp\r\nvoid Start()\r\n{\r\n    UnityEngine.Debug.Log(\"UniTaskPlayerLoop ready? \" + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());\r\n    PlayerLoopHelper.DumpCurrentPlayerLoop();\r\n}\r\n```\r\n\r\nYou can optimize loop cost slightly by remove unuse PlayerLoopTiming injection. You can call `PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)` on initialize.\r\n\r\n```csharp\r\nvar loop = PlayerLoop.GetCurrentPlayerLoop();\r\nPlayerLoopHelper.Initialize(ref loop, InjectPlayerLoopTimings.Minimum); // minimum is Update | FixedUpdate | LastPostLateUpdate\r\n```\r\n\r\n`InjectPlayerLoopTimings` has three preset, `All` and `Standard`(All without last except LastPostLateUpdate), `Minimum`(`Update | FixedUpdate | LastPostLateUpdate`). Default is All and you can combine custom inject timings like `InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate`.\r\n\r\nYou can make error to use uninjected `PlayerLoopTiming` by [Microsoft.CodeAnalysis.BannedApiAnalyzers](https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md). For example, you can setup `BannedSymbols.txt` like this for `InjectPlayerLoopTimings.Minimum`.\r\n\r\n```txt\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.Initialization; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.LastInitialization; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.EarlyUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.LastEarlyUpdate; Isn't injected this PlayerLoop in this project.d\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.LastFixedUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.PreUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.LastUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.PreLateUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreLateUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.PostLateUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.TimeUpdate; Isn't injected this PlayerLoop in this project.\r\nF:Cysharp.Threading.Tasks.PlayerLoopTiming.LastTimeUpdate; Isn't injected this PlayerLoop in this project.\r\n```\r\n\r\nYou can configure `RS0030` severity to error.\r\n\r\n![image](https://user-images.githubusercontent.com/46207/109150837-bb933880-77ac-11eb-85ba-4fd15819dbd0.png)\r\n\r\nasync void vs async UniTaskVoid\r\n---\r\n`async void` is a standard C# task system so it does not run on UniTask systems. It is better not to use it. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and reports errors immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require awaiting (fire and forget), using `UniTaskVoid` is better. Unfortunately to dismiss warning, you're required to call `Forget()`.\r\n\r\n```csharp\r\npublic async UniTaskVoid FireAndForgetMethod()\r\n{\r\n    // do anything...\r\n    await UniTask.Yield();\r\n}\r\n\r\npublic void Caller()\r\n{\r\n    FireAndForgetMethod().Forget();\r\n}\r\n```\r\n\r\nAlso UniTask has the `Forget` method, it is similar to `UniTaskVoid` and has the same effects. However `UniTaskVoid` is more efficient if you completely don't use `await`。\r\n\r\n```csharp\r\npublic async UniTask DoAsync()\r\n{\r\n    // do anything...\r\n    await UniTask.Yield();\r\n}\r\n\r\npublic void Caller()\r\n{\r\n    DoAsync().Forget();\r\n}\r\n```\r\n\r\nTo use an async lambda registered to an event, don't use `async void`. Instead you can use `UniTask.Action` or `UniTask.UnityAction`, both of which create a delegate via `async UniTaskVoid` lambda.\r\n\r\n```csharp\r\nAction actEvent;\r\nUnityAction unityEvent; // especially used in uGUI\r\n\r\n// Bad: async void\r\nactEvent += async () =\u003e { };\r\nunityEvent += async () =\u003e { };\r\n\r\n// Ok: create Action delegate by lambda\r\nactEvent += UniTask.Action(async () =\u003e { await UniTask.Yield(); });\r\nunityEvent += UniTask.UnityAction(async () =\u003e { await UniTask.Yield(); });\r\n```\r\n\r\n`UniTaskVoid` can also be used in MonoBehaviour's `Start` method.\r\n\r\n```csharp\r\nclass Sample : MonoBehaviour\r\n{\r\n    async UniTaskVoid Start()\r\n    {\r\n        // async init code.\r\n    }\r\n}\r\n```\r\n\r\nUniTaskTracker\r\n---\r\nuseful for checking (leaked) UniTasks. You can open tracker window in `Window -\u003e UniTask Tracker`.\r\n\r\n![image](https://user-images.githubusercontent.com/46207/83527073-4434bf00-a522-11ea-86e9-3b3975b26266.png)\r\n\r\n* Enable AutoReload(Toggle) - Reload automatically.\r\n* Reload - Reload view.\r\n* GC.Collect - Invoke GC.Collect.\r\n* Enable Tracking(Toggle) - Start to track async/await UniTask. Performance impact: low.\r\n* Enable StackTrace(Toggle) - Capture StackTrace when task is started. Performance impact: high.\r\n\r\nUniTaskTracker is intended for debugging use only as enabling tracking and capturing stacktraces is useful but has a heavy performance impact. Recommended usage is to enable both tracking and stacktraces to find task leaks and to disable them both when done.\r\n\r\nExternal Assets\r\n---\r\nBy default, UniTask supports TextMeshPro(`BindTo(TMP_Text)` and `TMP_InputField` event extensions like standard uGUI `InputField`), DOTween(`Tween` as awaitable) and Addressables(`AsyncOperationHandle` and `AsyncOperationHandle\u003cT\u003e` as awaitable).\r\n\r\nThere are defined in separated asmdefs like `UniTask.TextMeshPro`, `UniTask.DOTween`, `UniTask.Addressables`.\r\n\r\nTextMeshPro and Addressables support are automatically enabled when importing their packages from package manager. However for DOTween support, it is required to import `com.demigiant.dotween` from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or to define `UNITASK_DOTWEEN_SUPPORT` to enable it.\r\n\r\n```csharp\r\n// sequential\r\nawait transform.DOMoveX(2, 10);\r\nawait transform.DOMoveZ(5, 20);\r\n\r\n// parallel with cancellation\r\nvar ct = this.GetCancellationTokenOnDestroy();\r\n\r\nawait UniTask.WhenAll(\r\n    transform.DOMoveX(10, 3).WithCancellation(ct),\r\n    transform.DOScale(10, 3).WithCancellation(ct));\r\n```\r\n\r\nDOTween support's default behaviour(`await`, `WithCancellation`, `ToUniTask`) awaits tween is killed. It works on both Complete(true/false) and Kill(true/false). But if you want to reuse tweens (`SetAutoKill(false)`), it does not work as expected. If you want to await for another timing, the following extension methods exist in Tween, `AwaitForComplete`, `AwaitForPause`, `AwaitForPlay`, `AwaitForRewind`, `AwaitForStepComplete`.\r\n\r\nAsyncEnumerable and Async LINQ\r\n---\r\nUnity 2020.2 supports C# 8.0 so you can use `await foreach`. This is the new Update notation in the async era.\r\n\r\n```csharp\r\n// Unity 2020.2, C# 8.0\r\nawait foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate(token))\r\n{\r\n    Debug.Log(\"Update() \" + Time.frameCount);\r\n}\r\n```\r\n\r\nIn a C# 7.3 environment, you can use the `ForEachAsync` method to work in almost the same way.\r\n\r\n```csharp\r\n// C# 7.3(Unity 2018.3~)\r\nawait UniTaskAsyncEnumerable.EveryUpdate(token).ForEachAsync(_ =\u003e\r\n{\r\n    Debug.Log(\"Update() \" + Time.frameCount);\r\n});\r\n```\r\n\r\nUniTaskAsyncEnumerable implements asynchronous LINQ, similar to LINQ in `IEnumerable\u003cT\u003e` or Rx in `IObservable\u003cT\u003e`. All standard LINQ query operators can be applied to asynchronous streams. For example, the following code shows how to apply a Where filter to a button-click asynchronous stream that runs once every two clicks.\r\n\r\n```csharp\r\nawait okButton.OnClickAsAsyncEnumerable().Where((x, i) =\u003e i % 2 == 0).ForEachAsync(_ =\u003e\r\n{\r\n});\r\n```\r\n\r\nFire and Forget style(for example, event handling), you can also use `Subscribe`.\r\n\r\n```csharp\r\nokButton.OnClickAsAsyncEnumerable().Where((x, i) =\u003e i % 2 == 0).Subscribe(_ =\u003e\r\n{\r\n});\r\n```\r\n\r\nAsync LINQ is enabled when `using Cysharp.Threading.Tasks.Linq;`, and `UniTaskAsyncEnumerable` is defined in `UniTask.Linq` asmdef.\r\n\r\nIt's closer to UniRx (Reactive Extensions), but UniTaskAsyncEnumerable is a pull-based asynchronous stream, whereas Rx was a push-based asynchronous stream. Note that although similar, the characteristics are different and the details behave differently along with them.\r\n\r\n`UniTaskAsyncEnumerable` is the entry point like `Enumerable`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.\r\n\r\nThe method with Func as an argument has three additional overloads, `***Await`, `***AwaitWithCancellation`.\r\n\r\n```csharp\r\nSelect(Func\u003cT, TR\u003e selector)\r\nSelectAwait(Func\u003cT, UniTask\u003cTR\u003e\u003e selector)\r\nSelectAwaitWithCancellation(Func\u003cT, CancellationToken, UniTask\u003cTR\u003e\u003e selector)\r\n```\r\n\r\nIf you want to use the `async` method inside the func, use the `***Await` or `***AwaitWithCancellation`.\r\n\r\nHow to create an async iterator: C# 8.0 supports async iterator(`async yield return`) but it only allows `IAsyncEnumerable\u003cT\u003e` and of course requires C# 8.0. UniTask supports `UniTaskAsyncEnumerable.Create` method to create custom async iterator.\r\n\r\n```csharp\r\n// IAsyncEnumerable, C# 8.0 version of async iterator. ( do not use this style, IAsyncEnumerable is not controled in UniTask).\r\npublic async IAsyncEnumerable\u003cint\u003e MyEveryUpdate([EnumeratorCancellation]CancellationToken cancelationToken = default)\r\n{\r\n    var frameCount = 0;\r\n    await UniTask.Yield();\r\n    while (!token.IsCancellationRequested)\r\n    {\r\n        yield return frameCount++;\r\n        await UniTask.Yield();\r\n    }\r\n}\r\n\r\n// UniTaskAsyncEnumerable.Create and use `await writer.YieldAsync` instead of `yield return`.\r\npublic IUniTaskAsyncEnumerable\u003cint\u003e MyEveryUpdate()\r\n{\r\n    // writer(IAsyncWriter\u003cT\u003e) has `YieldAsync(value)` method.\r\n    return UniTaskAsyncEnumerable.Create\u003cint\u003e(async (writer, token) =\u003e\r\n    {\r\n        var frameCount = 0;\r\n        await UniTask.Yield();\r\n        while (!token.IsCancellationRequested)\r\n        {\r\n            await writer.YieldAsync(frameCount++); // instead of `yield return`\r\n            await UniTask.Yield();\r\n        }\r\n    });\r\n}\r\n```\r\n\r\nAwaitable Events\r\n---\r\nAll uGUI component implements `***AsAsyncEnumerable` to convert asynchronous streams of events.\r\n\r\n```csharp\r\nasync UniTask TripleClick()\r\n{\r\n    // In default, used button.GetCancellationTokenOnDestroy to manage lieftime of async\r\n    await button.OnClickAsync();\r\n    await button.OnClickAsync();\r\n    await button.OnClickAsync();\r\n    Debug.Log(\"Three times clicked\");\r\n}\r\n\r\n// more efficient way\r\nasync UniTask TripleClick()\r\n{\r\n    using (var handler = button.GetAsyncClickEventHandler())\r\n    {\r\n        await handler.OnClickAsync();\r\n        await handler.OnClickAsync();\r\n        await handler.OnClickAsync();\r\n        Debug.Log(\"Three times clicked\");\r\n    }\r\n}\r\n\r\n// use async LINQ\r\nasync UniTask TripleClick(CancellationToken token)\r\n{\r\n    await button.OnClickAsAsyncEnumerable().Take(3).Last();\r\n    Debug.Log(\"Three times clicked\");\r\n}\r\n\r\n// use async LINQ2\r\nasync UniTask TripleClick(CancellationToken token)\r\n{\r\n    await button.OnClickAsAsyncEnumerable().Take(3).ForEachAsync(_ =\u003e\r\n    {\r\n        Debug.Log(\"Every clicked\");\r\n    });\r\n    Debug.Log(\"Three times clicked, complete.\");\r\n}\r\n```\r\n\r\nAll MonoBehaviour message events can convert async-streams by `AsyncTriggers` that can be enabled by `using Cysharp.Threading.Tasks.Triggers;`. AsyncTrigger can be created using `GetAsync***Trigger` and triggers itself as UniTaskAsyncEnumerable.\r\n\r\n```csharp\r\nvar trigger = this.GetOnCollisionEnterAsyncHandler();\r\nawait trigger.OnCollisionEnterAsync();\r\nawait trigger.OnCollisionEnterAsync();\r\nawait trigger.OnCollisionEnterAsync();\r\n\r\n// every moves.\r\nawait this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =\u003e\r\n{\r\n});\r\n```\r\n\r\n`AsyncReactiveProperty`, `AsyncReadOnlyReactiveProperty` is UniTask's version of ReactiveProperty. `BindTo` extension method of `IUniTaskAsyncEnumerable\u003cT\u003e` for binding asynchronous stream values to Unity components(Text/Selectable/TMP/Text).\r\n\r\n```csharp\r\nvar rp = new AsyncReactiveProperty\u003cint\u003e(99);\r\n\r\n// AsyncReactiveProperty itself is IUniTaskAsyncEnumerable, you can query by LINQ\r\nrp.ForEachAsync(x =\u003e\r\n{\r\n    Debug.Log(x);\r\n}, this.GetCancellationTokenOnDestroy()).Forget();\r\n\r\nrp.Value = 10; // push 10 to all subscriber\r\nrp.Value = 11; // push 11 to all subscriber\r\n\r\n// WithoutCurrent ignore initial value\r\n// BindTo bind stream value to unity components.\r\nrp.WithoutCurrent().BindTo(this.textComponent);\r\n\r\nawait rp.WaitAsync(); // wait until next value set\r\n\r\n// also exists ToReadOnlyAsyncReactiveProperty\r\nvar rp2 = new AsyncReactiveProperty\u003cint\u003e(99);\r\nvar rorp = rp.CombineLatest(rp2, (x, y) =\u003e (x, y)).ToReadOnlyAsyncReactiveProperty(CancellationToken.None);\r\n```\r\n\r\nA pull-type asynchronous stream does not get the next values until the asynchronous processing in the sequence is complete. This could spill data from push-type events such as buttons.\r\n\r\n```csharp\r\n// can not get click event during 3 seconds complete.\r\nawait button.OnClickAsAsyncEnumerable().ForEachAwaitAsync(async x =\u003e\r\n{\r\n    await UniTask.Delay(TimeSpan.FromSeconds(3));\r\n});\r\n```\r\n\r\nIt is useful (prevent double-click) but not useful sometimes.\r\n\r\nUsing the `Queue()` method will also queue events during asynchronous processing.\r\n\r\n```csharp\r\n// queued message in asynchronous processing\r\nawait button.OnClickAsAsyncEnumerable().Queue().ForEachAwaitAsync(async x =\u003e\r\n{\r\n    await UniTask.Delay(TimeSpan.FromSeconds(3));\r\n});\r\n```\r\n\r\nOr use `Subscribe`, fire and forget style.\r\n\r\n```csharp\r\nbutton.OnClickAsAsyncEnumerable().Subscribe(async x =\u003e\r\n{\r\n    await UniTask.Delay(TimeSpan.FromSeconds(3));\r\n});\r\n```\r\n\r\nChannel\r\n---\r\n`Channel` is the same as [System.Threading.Tasks.Channels](https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels?view=netcore-3.1) which is similar to a GoLang Channel.\r\n\r\nCurrently it only supports multiple-producer, single-consumer unbounded channels. It can create by `Channel.CreateSingleConsumerUnbounded\u003cT\u003e()`.\r\n\r\nFor producer(`.Writer`), use `TryWrite` to push value and `TryComplete` to complete channel. For consumer(`.Reader`), use `TryRead`, `WaitToReadAsync`, `ReadAsync`, `Completion` and `ReadAllAsync` to read queued messages.\r\n\r\n`ReadAllAsync` returns `IUniTaskAsyncEnumerable\u003cT\u003e` so query LINQ operators. Reader only allows single-consumer but uses `.Publish()` query operator to enable multicast message. For example, make pub/sub utility.\r\n\r\n```csharp\r\npublic class AsyncMessageBroker\u003cT\u003e : IDisposable\r\n{\r\n    Channel\u003cT\u003e channel;\r\n\r\n    IConnectableUniTaskAsyncEnumerable\u003cT\u003e multicastSource;\r\n    IDisposable connection;\r\n\r\n    public AsyncMessageBroker()\r\n    {\r\n        channel = Channel.CreateSingleConsumerUnbounded\u003cT\u003e();\r\n        multicastSource = channel.Reader.ReadAllAsync().Publish();\r\n        connection = multicastSource.Connect(); // Publish returns IConnectableUniTaskAsyncEnumerable.\r\n    }\r\n\r\n    public void Publish(T value)\r\n    {\r\n        channel.Writer.TryWrite(value);\r\n    }\r\n\r\n    public IUniTaskAsyncEnumerable\u003cT\u003e Subscribe()\r\n    {\r\n        return multicastSource;\r\n    }\r\n\r\n    public void Dispose()\r\n    {\r\n        channel.Writer.TryComplete();\r\n        connection.Dispose();\r\n    }\r\n}\r\n```\r\n\r\nFor Unit Testing\r\n---\r\nUnity's `[UnityTest]` attribute can test coroutine(IEnumerator) but can not test async. `UniTask.ToCoroutine` bridges async/await to coroutine so you can test async methods.\r\n\r\n```csharp\r\n[UnityTest]\r\npublic IEnumerator DelayIgnore() =\u003e UniTask.ToCoroutine(async () =\u003e\r\n{\r\n    var time = Time.realtimeSinceStartup;\r\n\r\n    Time.timeScale = 0.5f;\r\n    try\r\n    {\r\n        await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: true);\r\n\r\n        var elapsed = Time.realtimeSinceStartup - time;\r\n        Assert.AreEqual(3, (int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven));\r\n    }\r\n    finally\r\n    {\r\n        Time.timeScale = 1.0f;\r\n    }\r\n});\r\n```\r\n\r\nUniTask's own unit tests are written using Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to integrate with CI and check if IL2CPP is working.\r\n\r\nThreadPool limitation\r\n---\r\nMost UniTask methods run on a single thread (PlayerLoop), with only `UniTask.Run`(`Task.Run` equivalent) and `UniTask.SwitchToThreadPool` running on a thread pool. If you use a thread pool, it won't work with WebGL and so on.\r\n\r\n`UniTask.Run` is now deprecated. You can use `UniTask.RunOnThreadPool` instead. And also consider whether you can use `UniTask.Create` or `UniTask.Void`.\r\n\r\nIEnumerator.ToUniTask limitation\r\n---\r\nYou can convert coroutine(IEnumerator) to UniTask(or await directly) but it has some limitations.\r\n\r\n* `WaitForEndOfFrame`/`WaitForFixedUpdate`/`Coroutine` is not supported.\r\n* Consuming loop timing is not the same as `StartCoroutine`, it uses the specified `PlayerLoopTiming` and the default `PlayerLoopTiming.Update` is run before MonoBehaviour's `Update` and `StartCoroutine`'s loop.\r\n\r\nIf you want fully compatible conversion from coroutine to async, use the `IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)` overload. It executes StartCoroutine on an instance of the argument MonoBehaviour and waits for it to complete in UniTask.\r\n\r\nFor UnityEditor\r\n---\r\nUniTask can run on Unity Editor like an Editor Coroutine. However, there are some limitations.\r\n\r\n* UniTask.Delay's DelayType.DeltaTime, UnscaledDeltaTime do not work correctly because they can not get deltaTime in editor. Therefore run on EditMode, automatically change DelayType to `DelayType.Realtime` that wait for the right time.\r\n* All PlayerLoopTiming run on the timing `EditorApplication.update`.\r\n* `-batchmode` with `-quit` does not work because Unity does not run `EditorApplication.update` and quit after a single frame. Instead, don't use `-quit` and quit manually with `EditorApplication.Exit(0)`.\r\n\r\nCompare with Standard Task API\r\n---\r\nUniTask has many standard Task-like APIs. This table shows what the alternative apis are.\r\n\r\nUse standard type.\r\n\r\n| .NET Type | UniTask Type | \r\n| --- | --- |\r\n| `IProgress\u003cT\u003e` | --- |\r\n| `CancellationToken` | --- | \r\n| `CancellationTokenSource` | --- |\r\n\r\nUse UniTask type.\r\n\r\n| .NET Type | UniTask Type | \r\n| --- | --- |\r\n| `Task`/`ValueTask` | `UniTask` |\r\n| `Task\u003cT\u003e`/`ValueTask\u003cT\u003e` | `UniTask\u003cT\u003e` |\r\n| `async void` | `async UniTaskVoid` | \r\n| `+= async () =\u003e { }` | `UniTask.Void`, `UniTask.Action`, `UniTask.UnityAction` |\r\n| --- | `UniTaskCompletionSource` |\r\n| `TaskCompletionSource\u003cT\u003e` | `UniTaskCompletionSource\u003cT\u003e`/`AutoResetUniTaskCompletionSource\u003cT\u003e` |\r\n| `ManualResetValueTaskSourceCore\u003cT\u003e` | `UniTaskCompletionSourceCore\u003cT\u003e` |\r\n| `IValueTaskSource` | `IUniTaskSource` |\r\n| `IValueTaskSource\u003cT\u003e` | `IUniTaskSource\u003cT\u003e` |\r\n| `ValueTask.IsCompleted` | `UniTask.Status.IsCompleted()` |\r\n| `ValueTask\u003cT\u003e.IsCompleted` | `UniTask\u003cT\u003e.Status.IsCompleted()` |\r\n| `new Progress\u003cT\u003e` | `Progress.Create\u003cT\u003e` |\r\n| `CancellationToken.Register(UnsafeRegister)` | `CancellationToken.RegisterWithoutCaptureExecutionContext` |\r\n| `CancellationTokenSource.CancelAfter` | `CancellationTokenSource.CancelAfterSlim` |\r\n| `Channel.CreateUnbounded\u003cT\u003e(false){ SingleReader = true }` | `Channel.CreateSingleConsumerUnbounded\u003cT\u003e` |\r\n| `IAsyncEnumerable\u003cT\u003e` | `IUniTaskAsyncEnumerable\u003cT\u003e` |\r\n| `IAsyncEnumerator\u003cT\u003e` | `IUniTaskAsyncEnumerator\u003cT\u003e` |\r\n| `IAsyncDisposable` | `IUniTaskAsyncDisposable` |\r\n| `Task.Delay` | `UniTask.Delay` |\r\n| `Task.Yield` | `UniTask.Yield` |\r\n| `Task.Run` | `UniTask.RunOnThreadPool` |\r\n| `Task.WhenAll` | `UniTask.WhenAll` |\r\n| `Task.WhenAny` | `UniTask.WhenAny` |\r\n| `Task.CompletedTask` | `UniTask.CompletedTask` |\r\n| `Task.FromException` | `UniTask.FromException` |\r\n| `Task.FromResult` | `UniTask.FromResult` |\r\n| `Task.FromCanceled` | `UniTask.FromCanceled` |\r\n| `Task.ContinueWith` | `UniTask.ContinueWith` |\r\n| `TaskScheduler.UnobservedTaskException` | `UniTaskScheduler.UnobservedTaskException` |\r\n\r\nPooling Configuration\r\n---\r\nUniTask aggressively caches async promise objects to achieve zero allocation (for technical details, see blog post [UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)). By default, it caches all promises but you can configure `TaskPool.SetMaxPoolSize` to your value, the value indicates cache size per type. `TaskPool.GetCacheSizeInfo` returns currently cached objects in pool.\r\n\r\n```csharp\r\nforeach (var (type, size) in TaskPool.GetCacheSizeInfo())\r\n{\r\n    Debug.Log(type + \":\" + size);\r\n}\r\n```\r\n\r\nAllocation on Profiler\r\n---\r\nIn UnityEditor the profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generates AsyncStateMachine as class on Debug build and as struct on Release build.\r\n\r\nUnity supports Code Optimization option starting in 2020.1 (right, footer).\r\n\r\n![](https://user-images.githubusercontent.com/46207/89967342-2f944600-dc8c-11ea-99fc-0b74527a16f6.png)\r\n\r\nYou can change C# compiler optimization to release to remove AsyncStateMachine allocation in development builds. This optimization option can also be set via `Compilation.CompilationPipeline-codeOptimization`, and `Compilation.CodeOptimization`.\r\n\r\nUniTaskSynchronizationContext\r\n---\r\nUnity's default SynchronizationContext(`UnitySynchronizationContext`) is a poor implementation for performance. UniTask bypasses `SynchronizationContext`(and `ExecutionContext`) so it does not use it but if exists in `async Task`, still used it. `UniTaskSynchronizationContext` is a replacement of `UnitySynchronizationContext` which is better for performance.\r\n\r\n```csharp\r\npublic class SyncContextInjecter\r\n{\r\n    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]\r\n    public static void Inject()\r\n    {\r\n        SynchronizationContext.SetSynchronizationContext(new UniTaskSynchronizationContext());\r\n    }\r\n}\r\n```\r\n\r\nThis is an optional choice and is not always recommended; `UniTaskSynchronizationContext` is less performant than `async UniTask` and is not a complete UniTask replacement. It also does not guarantee full behavioral compatibility with the `UnitySynchronizationContext`.\r\n\r\nAPI References\r\n---\r\nUniTask's API References are hosted at [cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html) by [DocFX](https://dotnet.github.io/docfx/) and [Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate).\r\n\r\nFor example, UniTask's factory methods can be seen at [UniTask#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.UniTask.html#methods-1). UniTaskAsyncEnumerable's factory/extension methods can be seen at [UniTaskAsyncEnumerable#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.Linq.UniTaskAsyncEnumerable.html#methods-1).\r\n\r\nUPM Package\r\n---\r\n### Install via git URL\r\n\r\nRequires a version of unity that supports path query parameter for git packages (Unity \u003e= 2019.3.4f1, Unity \u003e= 2020.1a21). You can add `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask` to Package Manager\r\n\r\n![image](https://user-images.githubusercontent.com/46207/79450714-3aadd100-8020-11ea-8aae-b8d87fc4d7be.png)\r\n\r\n![image](https://user-images.githubusercontent.com/46207/83702872-e0f17c80-a648-11ea-8183-7469dcd4f810.png)\r\n\r\nor add `\"com.cysharp.unitask\": \"https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask\"` to `Packages/manifest.json`.\r\n\r\nIf you want to set a target version, UniTask uses the `*.*.*` release tag so you can specify a version like `#2.1.0`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0`.\r\n\r\n### Install via OpenUPM\r\n\r\nThe package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli).\r\n\r\n```\r\nopenupm add com.cysharp.unitask\r\n```\r\n\r\n.NET Core\r\n---\r\nFor .NET Core, use NuGet.\r\n\r\n\u003e PM\u003e Install-Package [UniTask](https://www.nuget.org/packages/UniTask)\r\n\r\nUniTask of .NET Core version is a subset of Unity UniTask with PlayerLoop dependent methods removed.\r\n\r\nIt runs at higher performance than the standard Task/ValueTask, but you should be careful to ignore the ExecutionContext/SynchronizationContext when using it. `AsyncLocal` also does not work because it ignores ExecutionContext.\r\n\r\nIf you use UniTask internally, but provide ValueTask as an external API, you can write it like the following(Inspired by [PooledAwait](https://github.com/mgravell/PooledAwait)).\r\n\r\n```csharp\r\npublic class ZeroAllocAsyncAwaitInDotNetCore\r\n{\r\n    public ValueTask\u003cint\u003e DoAsync(int x, int y)\r\n    {\r\n        return Core(this, x, y);\r\n\r\n        static async UniTask\u003cint\u003e Core(ZeroAllocAsyncAwaitInDotNetCore self, int x, int y)\r\n        {\r\n            // do anything...\r\n            await Task.Delay(TimeSpan.FromSeconds(x + y));\r\n            await UniTask.Yield();\r\n\r\n            return 10;\r\n        }\r\n    }\r\n}\r\n\r\n// UniTask does not return to original SynchronizationContext but you can use helper `ReturnToCurrentSynchronizationContext`.\r\npublic ValueTask TestAsync()\r\n{\r\n    await using (UniTask.ReturnToCurrentSynchronizationContext())\r\n    {\r\n        await UniTask.SwitchToThreadPool();\r\n        // do anything..\r\n    }\r\n}\r\n```\r\n\r\n.NET Core version is intended to allow users to use UniTask as an interface when sharing code with Unity (such as [Cysharp/MagicOnion](https://github.com/Cysharp/MagicOnion/)). .NET Core version of UniTask enables smooth code sharing.\r\n\r\nUtility methods such as WhenAll which are equivalent to UniTask are provided as [Cysharp/ValueTaskSupplement](https://github.com/Cysharp/ValueTaskSupplement).\r\n\r\nLicense\r\n---\r\nThis library is under the MIT License.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgameframex%2Fcom.gameframex.unity.cysharp.unitask","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgameframex%2Fcom.gameframex.unity.cysharp.unitask","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgameframex%2Fcom.gameframex.unity.cysharp.unitask/lists"}