Loading lessons...
Async/Await and the Awaitable Class
Async/Await and the Awaitable Class
Unity 6 introduced the Awaitable class as a first-class alternative to coroutines for asynchronous code. Both C# Task-based async/await and Unity's Awaitable are supported.
Standard C# async/await in Unity
You can use standard C# async/await patterns in Unity scripts. Tasks resume in the Update phase by default.
using System.Threading.Tasks;
using UnityEngine;
public class AsyncExample : MonoBehaviour
{
async void Start()
{
Debug.Log("Starting async load...");
await LoadDataAsync();
Debug.Log("Data loaded!");
}
async Task LoadDataAsync()
{
// Simulates an async operation (e.g., web request)
await Task.Delay(2000); // waits 2 real seconds
}
}
Limitations of Task in Unity:
- Do not run on the main thread by default if using
Task.Run(). - Cannot access Unity API from background threads.
- No built-in integration with Unity's lifecycle (destroy, scene change).
Unity Awaitable Class
Unity's Awaitable is a lightweight, garbage-free alternative designed specifically for Unity:
using UnityEngine;
public class AwaitableExample : MonoBehaviour
{
async Awaitable Start()
{
// Wait for next frame (like yield return null in a coroutine)
await Awaitable.NextFrameAsync();
Debug.Log("Next frame reached");
// Wait until end of frame (after rendering)
await Awaitable.EndOfFrameAsync();
// Wait for a fixed update step
await Awaitable.FixedUpdateAsync();
// Wait for real seconds (unaffected by timeScale)
await Awaitable.WaitForSecondsAsync(1.5f);
}
}
Async Scene Loading
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneLoader : MonoBehaviour
{
async Awaitable LoadSceneAsync(string sceneName)
{
AsyncOperation op = SceneManager.LoadSceneAsync(sceneName);
op.allowSceneActivation = false;
// Wait until load is at 90% (Unity holds at 0.9 until activation)
while (op.progress < 0.9f)
{
await Awaitable.NextFrameAsync();
}
// Activate the scene
op.allowSceneActivation = true;
}
}
Cancellation with CancellationToken
Use a CancellationToken to cancel async operations when a script is destroyed:
using System.Threading;
using UnityEngine;
public class CancelExample : MonoBehaviour
{
private CancellationTokenSource _cts;
void Start()
{
_cts = new CancellationTokenSource();
RunAsync(_cts.Token);
}
async void RunAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
await Awaitable.NextFrameAsync(token);
// Do work each frame
}
}
void OnDestroy()
{
_cts.Cancel();
_cts.Dispose();
}
}
TL;DR
- Standard C#
async/await(Task-based) works in Unity but has threading caveats. Awaitableis Unity's lightweight, garbage-free async primitive.- Use
Awaitable.NextFrameAsync(),FixedUpdateAsync(),WaitForSecondsAsync()as coroutine-equivalents. - Always cancel async work in
OnDestroyusing aCancellationToken.