Task Utils
A safe and elegant solution for handling C# Tasks and asynchronous operations in Unity
In One Line
Threading wizardry: Promise made, Promise kept!
Overview
While C# Tasks are powerful, they require careful handling in Unity's single-threaded environment. Task Utils provides a robust framework for managing asynchronous operations safely, with a focus on exception handling and main thread synchronization.
Promise Awaiter transforms traditional async/await patterns into a more manageable and safer approach.
This implementation ensures that:
Async operations can safely return to the main thread
Unity API calls are always thread-compliant
No threading-related crashes or race conditions
Predictable execution order in the Unity lifecycle
PromiseAgent will run Coroutine cross different scene
Coroutine can be converted to Task
Package Info
display name
AceLand Task Utils
package name
latest version
1.0.9
namespace
git repository
dependencies
Why Use It
The most important reason is thread-safe and exception-safe for Unity.
Traditional exception handling in production builds can be problematic:
Unhandled exceptions can freeze critical application flows
Users are left with no feedback when errors occur
Debug information is often lost in production builds
Promise Awaiter solves these issues by:
Keeping your application running despite errors
Enabling user-friendly error handling
Maintaining proper error logging for debugging
Ensuring operations stay on the main thread when needed
Developer Benefits:
No more await/try-catch complexity
Clean, chainable syntax
Safe main thread synchronization
Integrated with other AceLand packages
Ideal for both development and production environments
How It Works
Task can be converted to Promise style chain methods:
Then(async action) - completed with success result
Then(action) - completed with success result
Catch(action) - completed with exception
Final(action) - completed either success or exception
Callbacks will pass to Unity Main Thread Dispacher and queued to execute during the Initialization phase of Unity's PlayerLoop. This guarantees that all handlers always run on the main thread. Developers are free from manual thread synchronization or checking IsMainThread, and safe to access Unity APIs, UI elements, and GameObjects.
On case of success, async action will be invoked first, and wait until completed. If completed with exception, it will jump to Catch process. Then(action) will not be invoked in this case.
In Then(async action), Exception will not be throw if await a Promise. Please await a native Task instead.
Then and Catch will not be invoked if Task or Promise is canceled or disposed.
Final action will not be invoked if Promise is disposed.
Please prevent from deep nested Promise blocks for clean code.
Usage Example
Promise Awaiter will catch all exception, and pass Then Catch Final actions to Main Thread Dispatcher. That means the task will be finished without any return.
If awaiting promise in Then async block, the whole promise may be finished without exception return. In exception case, the process will be hold on the await promise.
Easy Safe Task
A lazy way to run Task or heavy stuff.
SafeRun will run all stuff in Thread Pool. Most Unity API cannot be excute.
Please use Coroutine if Unity API is necessary. See next section below.
Work with Coroutine
A lot of Unity APIs are supporting on only Main Thread that processes need to switch between main thread and thread pool. This makes Coroutine is the only choice to do heavy jobs with Unity APIs.
However it is not thread safe by yield return a Task in coroutine. Task can be yield return in coroutine, but exception cannot be handled. And value cannot be returned.
Promise Handle is one of the solution.
Promise is already a thread safe handler. By chaining with .Catch() after a Task, exceptions will be catched by handler.
Coroutine or IEnumerable will always run in Main Thread.
AsTask will always return a Task instead of Task<T>. Then will not receive any value from IEnumerator.
Utilities
️ Important Task Safety Notes
Tasks in Unity Editor pose significant risks during Play Mode:
Tasks initiated during Play Mode continue running even after stopping
Background tasks persist without proper cleanup
Can lead to memory leaks and unexpected behaviors
Always Use Cancellation Tokens
Resource Management
Properly dispose resources on application quit
Use linked tokens for dependent operations
Monitor task lifecycles, especially in Editor
Ensure clean task management both in Editor and build environments, preventing resource leaks and unexpected behaviors.
Best Practices
Promise Awaiter will catch system exception and pass to Main Thread Patch. This is a thread-safe design for Unity. That's why exception cannot be catch when await Promise or nested Promise.
As above, building native Task design is very important. Promise Awaiter is to prevent from unsafe threading code and clear code structure.
Work with Coroutine for using Unity APIs in Main Thread but keep heavy works in Thread Pool. Tasks may be split by many little parts for exceptions handling.
Last updated