Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Async WebRequest and await in the script where data is needed

Discussion in 'Scripting' started by EdiJung, Jul 21, 2022.

  1. EdiJung

    EdiJung

    Joined:
    Nov 10, 2020
    Posts:
    4
    My final Goal is to have a Start Screen where i start loading the data.
    If the User goes to the next screen, i have to check, if loading data already done (and show a loading indicator if its not done)

    At the moment for testing, i start the loading data in the Awake() function in the same Script.
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.Threading.Tasks;
    3. using UnityEngine;
    4.  
    5. public class PopulateShelf : MonoBehaviour
    6. {
    7.     private List<Task> tasks = new List<Task>();
    8.  
    9.     private void Awake()
    10.     {
    11.         tasks.Add(LoadingData.LoadData());
    12.     }
    13.     private void Start()
    14.     {
    15.         waitOnData().GetAwaiter().GetResult();
    16.         //Do Something with the data
    17.     }
    18.  
    19.     private async Task waitOnData()
    20.     {
    21.         await Task.WhenAll(tasks);
    22.     }
    23. }
    24.  
    According to this Video:
    with GetAwaiter().GetResult() i can await a async method from a non async method.
    And with await.Task.WhenAll(tasks) i try to wait until all data is loaded

    My WebRequest (LoadingData.LoadData()) looks like the following:
    Code (CSharp):
    1.  
    2. public class LoadingData : MonoBehaviour
    3. {
    4.     public static Dictionary<int, BookDTO> Books = new Dictionary<int, BookDTO>();
    5.     public static List<CategoryDTO> Categories = new List<CategoryDTO>();
    6.     public static async Task LoadData()
    7.     {
    8.         await LoadCategories();
    9.         LoadBooks();
    10.         await Task.Yield();
    11.     }
    12.     public static async Task LoadCategories()
    13.     {
    14.         UnityWebRequest request = UnityWebRequest.Get(Constants.apiURL + Constants.apiURLCategories);
    15.         await Task.Yield();
    16.         request.SendWebRequest();
    17.         if (request.result == UnityWebRequest.Result.ConnectionError)
    18.         {
    19.             Debug.Log(request.error);
    20.         }
    21.         else
    22.         {
    23.             Categories = JsonConvert.DeserializeObject<List<CategoryDTO>>(request.downloadHandler.text);
    24.         }
    25.  
    26.     }
    27.     public static async Task LoadBooks()
    28.     {
    29.         UnityWebRequest request = UnityWebRequest.Get(Constants.apiURL + Constants.apiURLBooks);
    30.         await Task.Yield();
    31.         request.SendWebRequest();
    32.         if (request.result == UnityWebRequest.Result.ConnectionError)
    33.         {
    34.             Debug.Log(request.error);
    35.         }
    36.         else
    37.         {
    38.             List<BookDTO> books = JsonConvert.DeserializeObject<List<BookDTO>>(request.downloadHandler.text);
    39.             books.ForEach(b => Books.Add(b.bookId, b));
    40.         }
    41.     }
    42. }
    43.  
    I have the feeling that it is quite messy... so for any improvements I am also very grateful
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    Why not just use coroutines? Super-simple to reason about. Your web-get coroutine can accept a delegate that it calls back when the data is ready.
     
  3. EdiJung

    EdiJung

    Joined:
    Nov 10, 2020
    Posts:
    4
    Thanks for the answer.
    I first try it with coroutines but the video mention above says async/await are 'simpler'...
    But anyways, if i try it with coroutines.
    Then i would start the coroutine in the await.
    But how do i check if the coroutines is finished, when i need the data?
     
    Mentoster likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    Go look at the example code for UnityWebRequest.
     
  5. nTu4Ka

    nTu4Ka

    Joined:
    Jan 27, 2014
    Posts:
    68
    It's probably late but async/await definitely easier to manage and more flexible. Tarodev has good examples why.
    I rewrote a portion of my code to get rid of coroutines and am really happy so far. :) async/await allowed me to decentralize code and get rid of unnecessary wrappers. Code got a lot cleaner and easier to read. :)

    There are some caveats though:
    -ThreadPool is not supported in WebGL as of now. So things like Task.Run() and ThreadPool commands will not work in web builds.
    -There are some deeper issues with async/await which you can find in top comment under Tarodev video.

    I can also propose to use UniTask instead of Task. It's a nice "wrapper" with great WebGL support, multiple features and clear documentation:
    https://github.com/Cysharp/UniTask#getting-started