mirror of https://github.com/Cysharp/UniTask
ReadMe
parent
2337d705ec
commit
680ce1098b
31
README.md
31
README.md
|
@ -53,21 +53,32 @@ async UniTask<string> DemoAsync()
|
||||||
{
|
{
|
||||||
// You can await Unity's AsyncObject
|
// You can await Unity's AsyncObject
|
||||||
var asset = await Resources.LoadAsync<TextAsset>("foo");
|
var asset = await Resources.LoadAsync<TextAsset>("foo");
|
||||||
|
var txt = (await UnityWebRequest.Get("https://...").SendWebRequest()).downloadHandler.text;
|
||||||
|
await SceneManager.LoadSceneAsync("scene2");
|
||||||
|
|
||||||
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
|
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
|
||||||
var asset2 = await Resources.LoadAsync<TextAsset>("foo").WithCancellation(this.GetCancellationTokenOnDestroy());
|
var asset2 = await Resources.LoadAsync<TextAsset>("bar").WithCancellation(this.GetCancellationTokenOnDestroy());
|
||||||
|
|
||||||
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
|
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
|
||||||
await SceneManager.LoadSceneAsync("scene2").ToUniTask(Progress.Create<float>(x => Debug.Log(x)));
|
var asset3 = await Resources.LoadAsync<TextAsset>("baz").ToUniTask(Progress.Create<float>(x => Debug.Log(x)));
|
||||||
|
|
||||||
// await frame-based operation like coroutine
|
// await frame-based operation like coroutine
|
||||||
await UniTask.DelayFrame(100);
|
await UniTask.DelayFrame(100);
|
||||||
|
|
||||||
// replacement of WaitForSeconds/WaitForSecondsRealtime
|
// replacement of yield return new WaitForSeconds/WaitForSecondsRealtime
|
||||||
await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false);
|
await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false);
|
||||||
|
|
||||||
// replacement of WaitForEndOfFrame(or other timing like yield return null, yield return WaitForFixedUpdate)
|
// yield any playerloop timing(PreUpdate, Update, LateUpdate, etc...)
|
||||||
await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
|
await UniTask.Yield(PlayerLoopTiming.PreLateUpdate);
|
||||||
|
|
||||||
|
// replacement of yield return null
|
||||||
|
await UniTask.NextFrame();
|
||||||
|
|
||||||
|
// replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate))
|
||||||
|
await UniTask.WaitForEndOfFrame();
|
||||||
|
|
||||||
|
// replacement of yield return new WaitForFixedUpdate
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.FixedUpdate);
|
||||||
|
|
||||||
// replacement of yield return WaitUntil
|
// replacement of yield return WaitUntil
|
||||||
await UniTask.WaitUntil(() => isActive == false);
|
await UniTask.WaitUntil(() => isActive == false);
|
||||||
|
@ -127,6 +138,8 @@ UniTask provides three pattern of extension methods.
|
||||||
|
|
||||||
`WithCancellation` is a simple version of `ToUniTask`, both returns `UniTask`. Details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section.
|
`WithCancellation` is a simple version of `ToUniTask`, both returns `UniTask`. Details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section.
|
||||||
|
|
||||||
|
> Note: WithCancellation is returned from native timing of PlayerLoop but ToUniTask is returned from specified PlayerLoopTiming. Details of timing, see: [PlayerLoop](#playerloop) section.
|
||||||
|
|
||||||
The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type.
|
The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
|
@ -321,10 +334,16 @@ public enum PlayerLoopTiming
|
||||||
|
|
||||||
It 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.
|
It 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.
|
||||||
|
|
||||||
`PlayerLoopTiming.Update` is similar as `yield return null` in coroutine, but it is called before Update(Update is called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). If change timing to `PlayerLoopTiming.LastUpdate`, called after these Unity's update methods.
|
`PlayerLoopTiming.Update` is similar as `yield return null` in 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 as `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar as `WaitForEndOfFrame` in coroutine.
|
`PlayerLoopTiming.FixedUpdate` is similar as `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar as `WaitForEndOfFrame` in coroutine.
|
||||||
|
|
||||||
|
`yield return null` and `UniTask.Yield` is similar but different. `yield return null` always return next frame but `UniTask.Yield` return next called, that is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` gurantees return next frame, this would be expected to behave exactly the same as `yield return null`.
|
||||||
|
|
||||||
|
AsyncOperation is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after called, loaded scene called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
|
||||||
|
|
||||||
|
In UniTask, await directly and `WithCancellation` use native timing, `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, causes different order of Start and continuation after await. so recommend not to use `LoadSceneAsync.ToUniTask`.
|
||||||
|
|
||||||
In stacktrace, you can check where is running in playerloop.
|
In stacktrace, you can check where is running in playerloop.
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/46207/83735571-83caea80-a68b-11ea-8d22-5e22864f0d24.png)
|
![image](https://user-images.githubusercontent.com/46207/83735571-83caea80-a68b-11ea-8d22-5e22864f0d24.png)
|
||||||
|
|
|
@ -21,13 +21,15 @@ public class ExceptionExamples : MonoBehaviour
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
UnityEngine.Debug.Log("ExceptionScene, LoopType:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
|
||||||
|
|
||||||
ThrowFromAsyncVoid();
|
//TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
||||||
_ = ThrowFromTask();
|
|
||||||
_ = ThrowFromUniTask();
|
|
||||||
|
|
||||||
ThrowFromNonAsync();
|
//ThrowFromAsyncVoid();
|
||||||
|
//_ = ThrowFromTask();
|
||||||
|
//_ = ThrowFromUniTask();
|
||||||
|
|
||||||
|
//ThrowFromNonAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
||||||
|
|
|
@ -14,6 +14,7 @@ using UnityEngine;
|
||||||
using UnityEngine.LowLevel;
|
using UnityEngine.LowLevel;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
|
|
||||||
// using DG.Tweening;
|
// using DG.Tweening;
|
||||||
|
@ -265,11 +266,14 @@ public class SandboxMain : MonoBehaviour
|
||||||
//var r = UniAsync("https://bing.com/", cts.Token);
|
//var r = UniAsync("https://bing.com/", cts.Token);
|
||||||
//cts.Cancel();
|
//cts.Cancel();
|
||||||
//await r;
|
//await r;
|
||||||
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
|
Debug.Log("SendWebRequestDone:" + PlayerLoopInfo.CurrentLoopType);
|
||||||
Debug.Log("UNIASYNC1 ");
|
|
||||||
|
|
||||||
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
|
|
||||||
Debug.Log("UNIASYNC2");
|
// var foo = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
|
||||||
|
// foo.downloadHandler.text;
|
||||||
|
//
|
||||||
|
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().WithCancellation(CancellationToken.None);
|
||||||
|
Debug.Log("SendWebRequestWithCancellationDone:" + PlayerLoopInfo.CurrentLoopType);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -310,17 +314,107 @@ public class SandboxMain : MonoBehaviour
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerator CoroutineRun()
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Before Coroutine yield return null," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
|
||||||
|
yield return null;
|
||||||
|
UnityEngine.Debug.Log("After Coroutine yield return null," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator CoroutineRun2()
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Before Coroutine yield return WaitForEndOfFrame," + Time.frameCount);
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
UnityEngine.Debug.Log("After Coroutine yield return WaitForEndOfFrame," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
UnityEngine.Debug.Log("Onemore After Coroutine yield return WaitForEndOfFrame," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async UniTaskVoid AsyncRun()
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Before async Yield(default)," + Time.frameCount);
|
||||||
|
await UniTask.Yield();
|
||||||
|
UnityEngine.Debug.Log("After async Yield(default)," + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType);
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid AsyncLastUpdate()
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Before async Yield(LastUpdate)," + Time.frameCount);
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.LastUpdate);
|
||||||
|
UnityEngine.Debug.Log("After async Yield(LastUpdate)," + Time.frameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid AsyncLastLast()
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("Before async Yield(LastPostLateUpdate)," + Time.frameCount);
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
|
||||||
|
UnityEngine.Debug.Log("After async Yield(LastPostLateUpdate)," + Time.frameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid Yieldding()
|
||||||
|
{
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||||
|
StartCoroutine(CoroutineRun());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
_ = Ex();
|
PlayerLoopInfo.Inject();
|
||||||
|
|
||||||
_ = UniTask.Run(async () =>
|
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||||
{
|
{
|
||||||
var watch = System.Diagnostics.Stopwatch.StartNew();
|
/*
|
||||||
await UniTask.Delay(new TimeSpan(0, 0, seconds: 10));
|
UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
|
||||||
Debug.Log(watch.Elapsed);
|
StartCoroutine(CoroutineRun());
|
||||||
});
|
StartCoroutine(CoroutineRun2());
|
||||||
|
_ = AsyncRun();
|
||||||
|
_ = AsyncLastUpdate();
|
||||||
|
_ = AsyncLastLast();
|
||||||
|
*/
|
||||||
|
await UniTask.Yield();
|
||||||
|
_ = Test2();
|
||||||
|
// EarlyUpdate.ExecuteMainThreadJobs
|
||||||
|
// _ = Test2();
|
||||||
|
|
||||||
|
//var t = await Resources.LoadAsync<TextAsset>(Application.streamingAssetsPath + "test.txt");
|
||||||
|
//Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + (t != null));
|
||||||
|
//Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + ((TextAsset)t).text);
|
||||||
|
|
||||||
|
|
||||||
|
//await UniTask.Yield(PlayerLoopTiming.LastUpdate);
|
||||||
|
//UnityEngine.Debug.Log("after update:" + Time.frameCount);
|
||||||
|
////await UniTask.NextFrame();
|
||||||
|
////await UniTask.Yield();
|
||||||
|
////UnityEngine.Debug.Log("after update nextframe:" + Time.frameCount);
|
||||||
|
|
||||||
|
//StartCoroutine(CoroutineRun2());
|
||||||
|
////StartCoroutine(CoroutineRun());
|
||||||
|
//UnityEngine.Debug.Log("FOO?");
|
||||||
|
}));
|
||||||
|
|
||||||
|
cancelButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||||
|
{
|
||||||
|
//await UniTask.Yield(PlayerLoopTiming.LastPreUpdate);
|
||||||
|
//UnityEngine.Debug.Log("before update:" + Time.frameCount);
|
||||||
|
//await UniTask.NextFrame();
|
||||||
|
//await UniTask.Yield();
|
||||||
|
//UnityEngine.Debug.Log("before update nextframe:" + Time.frameCount);
|
||||||
|
|
||||||
|
//StartCoroutine(CoroutineRun());
|
||||||
|
|
||||||
|
//UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
|
||||||
|
//_ = Yieldding();
|
||||||
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
|
||||||
|
var la = SceneManager.LoadSceneAsync("Scenes/ExceptionExamples").WithCancellation(cts.Token);
|
||||||
|
//cts.Cancel();
|
||||||
|
await la;
|
||||||
|
UnityEngine.Debug.Log("End LoadSceneAsync" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
|
||||||
|
}));
|
||||||
|
|
||||||
//return;
|
//return;
|
||||||
//await UniTask.SwitchToMainThread();
|
//await UniTask.SwitchToMainThread();
|
||||||
|
@ -433,7 +527,7 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
//okButton.onClick.AddListener(UniTask.UnityAction(async () => await UniTask.Yield()));
|
//okButton.onClick.AddListener(UniTask.UnityAction(async () => await UniTask.Yield()));
|
||||||
|
|
||||||
PlayerLoopInfo.Inject();
|
|
||||||
|
|
||||||
//UpdateUniTask().Forget();
|
//UpdateUniTask().Forget();
|
||||||
|
|
||||||
|
@ -447,10 +541,6 @@ public class SandboxMain : MonoBehaviour
|
||||||
//GameObject.Destroy(this.gameObject);
|
//GameObject.Destroy(this.gameObject);
|
||||||
|
|
||||||
|
|
||||||
SynchronizationContext.Current.Post(_ =>
|
|
||||||
{
|
|
||||||
//UnityEngine.Debug.Log("Post:" + PlayerLoopInfo.CurrentLoopType);
|
|
||||||
}, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async UniTaskVoid UpdateUniTask()
|
async UniTaskVoid UpdateUniTask()
|
||||||
|
|
|
@ -369,6 +369,24 @@ namespace Cysharp.Threading.TasksTests
|
||||||
throw new Exception("MyException");
|
throw new Exception("MyException");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator NextFrame1() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.LastUpdate);
|
||||||
|
var frame = Time.frameCount;
|
||||||
|
await UniTask.NextFrame();
|
||||||
|
Time.frameCount.Should().Be(frame + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator NextFrame2() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||||
|
var frame = Time.frameCount;
|
||||||
|
await UniTask.NextFrame();
|
||||||
|
Time.frameCount.Should().Be(frame + 1);
|
||||||
|
});
|
||||||
|
|
||||||
[UnityTest]
|
[UnityTest]
|
||||||
public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () =>
|
public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@ EditorBuildSettings:
|
||||||
- enabled: 1
|
- enabled: 1
|
||||||
path: Assets/Scenes/SandboxMain.unity
|
path: Assets/Scenes/SandboxMain.unity
|
||||||
guid: 2cda990e2423bbf4892e6590ba056729
|
guid: 2cda990e2423bbf4892e6590ba056729
|
||||||
- enabled: 0
|
- enabled: 1
|
||||||
path:
|
path: Assets/Scenes/ExceptionExamples.unity
|
||||||
guid: 00000000000000000000000000000000
|
guid: b5fed17e3ece238439bc796d8747df5d
|
||||||
m_configObjects: {}
|
m_configObjects: {}
|
||||||
|
|
Loading…
Reference in New Issue