Because the cancellation simply does not work. In this case the CancellationToken has to be supplied to the Delay-Call:
UniTask.Delay(1000, cancellationToken: source.Token)
Within the Delay-Call the cancellation will cause an OperationCanceledException, which will then break further execution of the created UniTask.
I also advice using Methods for asynchronous calls which are getting the CancellationToken as last parameter. You can then have the possibility to handle cancellations in your code like this:
private async UniTask DoSomethingAsync(CancellationToken cancellationToken)
{
Debug.Log("QQQQQQQQQQQQQ");
await UniTask.Delay(1000, cancellationToken: cancellationToken);
// ---
if (cancellationToken.IsCancellationRequested)
{
// do some things
}
// OR
cancellationToken.ThrowIfCancellationRequested(); // breaks further execution of this method
// ---
Debug.Log("WWWWW");
}
And calling the method that way:
// If you are in an async method and have interesst in the result
var task = DoSomethingAsync(this.source.Token);
// You may do some stuff in between, because it runs asynchronously
var taskResult = await task; // if there is a return value
await task; // if there is no return value
// If you are NOT in an async method and have no interesst in the result
DoSomethingAsync(this.source.Token).Forget();
If you mean System.Threading.Tasks.Task (called classic tasks hereafter) then this one comes directly from .NET Framework and is a important class for doing asynchronous work while using Operation System threads in the background. But a task is not a thread itself, it can be seen a s a portion of work to be done asynchronously and may be queued first and later executed. By default it’s not guaranteed to be executed immediately. Classic tasks can be used with and without the C# keywords async/await. But both ways should be used and treated separately.
Unity coroutine is the Unity way of doing asynchronous work which can even be tied directly to frames. Unity uses a unique way of doing this with IEnumerable result and using the yield keyword within the coroutine method. This one is completly NOT compatible with classic tasks and the C# keywords async/await.
One note: You can still use classic tasks in Unity but will soon face many issues, because within the tasks you are doing stuff in worker threads. But working with Unity objects mostly requires that you are doing things in the main thread which you have left in the classic tasks. You may still do some calculation things unrelated to Unity in such tasks, but can never touch Unity objects there.
And here comes UniTask. This one closes the gap between Unity coroutine and the classic tasks. So you can use async/await mechanics of C#. As far as I understood the Unity methods like MonoBehaviour.Update and Coroutine are used in the background. Also UniTask works allocation free, so it should be perform quite well other than classic tasks may do in Unity. I cannot explain the details, but you can find some documentation here:
https://github.com/Cysharp/UniTask