Search Unity

  1. Unity 2019.1 beta is now available.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. We're looking for insight from anyone who has experience with game testing to help us better Unity. Take our survey here. If chosen to participate you'll be entered into a sweepstake to win an Amazon gift card.
    Dismiss Notice
  4. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  5. Unity 2018.3 is now released.
    Dismiss Notice
  6. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

How to wait for a function with a task to be completed before continuing

Discussion in 'Scripting' started by shlighter, Feb 7, 2019.

  1. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    I'm asking how to wait until a function with a task inside is done, before continuing

    Code (CSharp):
    1. public void A()
    2. {
    3. Debug.Log("before")
    4. CopyInfoFromDB();
    5. Debug.Log("after")
    6. }
    7.  
    8. public void CopyInfoFromDB()
    9. {
    10.           FirebaseDatabase.DefaultInstance.GetReference(path)
    11.  
    12.              .GetValueAsync().ContinueWith(task =>
    13.              {
    14.                  if (task.IsFaulted||task.IsCanceled)
    15. )
    16.                  {
    17.                      Debug.Log("failed");
    18.                      return;
    19.                  }
    20.             name = ...// initializinglocal varibles from Task.result
    21.             });
    22. }
    I want it to wait for CopyInfoFromDB to be completed before printing "after". How should I write function A differently? (I can't return a task from CopyInfoFromDB since I deal with Task.result inside that function and don't need to return anything)
     
    Last edited: Feb 7, 2019
  2. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,291
    Where you are checking whether it failed:
    Code (csharp):
    1.  
    2. Debug.Log(task.IsFaulted ? "failed" : "after");
    3.  
     
  3. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    How is it relevant to my question? If it fails it ends the task, otherwise I use task.Result and export some data from there
     
  4. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,257
    Either pass a callback as an additional argument to your method, or add an event to the class that contains the method.

    If the firebase api is based on later versions of Unity and the runtime and utilizes tasks, you should be able to await the task using the 'await' keyword. I've never used firebase though, and I don't know whether they just have similarly named methods, or if they're actually using tasks.
     
  5. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    Thanks for your answer, it seems like I can add AsyncCallback. My question is about Unity, not Firebase, the code is C# so I have await. The question is where to use it in my code so it won't print "after"
     
  6. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    785
    Basically what you are trying to say is that you want a synchronous function to sync to an asynchronous function.

    You need to be careful with how you write these types of methods cause if you start to use asyncs and awaits frivolously you can end up with deadlocks. Among the simplest and best practices to do is to make the entire inside method that is using an async behave asynchronously. My team uses (an in-house version of) the Promise API to do most the heavy lifting.

    A promise is for all intents and purposes an event system that is decoupled from both the issuer and the listeners. you create a promise which is initalized in a pending state. when a promise is in a resolved state (i.e. successful) all handlers attached to the promise via IPromise.Then() fire off. If a promise is in a rejected state all the IPromise.Catch() fire off. You can make a chain of Then/Catch making everything in that chain run in sequence. Plus if you add a Then/Catch handler to a promise that had already resolved/rejected, the respective added handler fires immediately (this is useful in that your handlers don't need to know the context of when the promise was issued).


    Code (CSharp):
    1. public IPromise WaitForDBInfo()
    2. {
    3.     var promise = new Promise();
    4.     myFirebaseReference.getValueAsync().ContinueWith(
    5.         task =>{
    6.         if (task.IsFaulted||task.IsCanceled)
    7.         {
    8.             promise.Reject(new Exception("failed");
    9.             return;
    10.         }
    11.         //initalze data
    12.  
    13.         promise.Resolve();
    14.     });
    15.  
    16. return promise;
    17. }
    its very similar to your CopyInfoFromDB() method, but here we return an IPromise handle which we can bind callback handler code to. I also renamed the method so that it can read better in A()...

    then your A() would wrap the after call inside a promise handler like so...
    Code (CSharp):
    1. public void A()
    2. {
    3. Debug.Log("before");
    4. WaitForDBInfo()
    5.     .Then(()=>Debug.Log("after")) // waits till WaitForDBInfo() finishes succesfully before it runs the action inside Then.
    6.     .Catch(Debug.LogException); //If the Promise was rejected or threw an exception we catch it and display to the console using the Debug class
    7.     .Done();// since .Then() and .Catch() conatenates a promise chain we tell that we are done adding to the chain so the promise can resolve.
    8. }
    basically I've made all the synchronous code written after the async methods which wants to wait on that method (e.g. the "after") asynchronous by wrapping it in a "Then handler".

    so now what happens in A() is that "before" prints to console as usual, and the DB request is sent out. Then the function completes, not needing to wait on the result to come back before returning. when the result does finally comeback the firebase response is then processed, if the response was successful the data is then initialized, and "After" prints to console. however if the response failed then the data is not initialized,"after" is NOT printed, and instead the exception "failed" is printed to console.

    A() remains synchronized as well as anything calling A() and expecting it to behave synchronously. its not waiting on Firebase before returning control back the the caller. the "after" stuff is simply run as a callback once the inital promise is resolved.
     
  7. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    Hey, Joshua thanks for the detailed answer! I'm still processing it, but I have a question.
    "you want a synchronous function to sync to an asynchronous function"
    Would it help if I change function A to be asynchronous. Maybe it'd help if I explain the function-
    I have a "BUY" button, it calls function A , function A checks with CopyInfoFromDB() that there is enough money in the Database (using task). . and then completes function A and buys the objects if found enough money in DB (that's why I needed to wait)
     
  8. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,257
    Well, it depends... The API of Firebase could be relevant, simply because if it already uses tasks (which it apparently does), you can stop working around it and just make your method await it all the way up, and return either a task or make your method the "root" of an async call stack (async void, which is not awaitable at the call site).

    There are basically two different ways to handle each new method / task.

    The first is to simply return a task and make the caller decide what to do with it. This can be imagined as if you just pass a task around, without triggering its execution at any point and leave it up to the caller. This is mainly useful, when you want to prepare the tasks for later use.

    The second is to just await the task at any level, so that you're forced (or rather encouraged, because not awaiting it would just generate a warning) to run this asynchronously. This is mainly useful to make things happen upon calling an async method, and/or if you need to await something before a method returns another awaitable result.

    Let's first look at the first case:
    Code (CSharp):
    1. private string _name = null;
    2. private async void Awake()
    3. {
    4.     Debug.Log("before");
    5.  
    6.     await CopyInfoFromDB_ReturnTask();
    7.  
    8.     Debug.Log("after");
    9.     Debug.Log(_name);
    10. }
    11.  
    12. public Task CopyInfoFromDB_ReturnTask() // note the return type, not async
    13. {
    14.     // only creates and returns the task, just as if it was a normal return type, hence no "async" in front of the method's return type
    15.     return FirebaseDatabase.DefaultInstance.GetReference(path).GetValueAsync().ContinueWith(task =>
    16.     {
    17.         if (task.IsFaulted || task.IsCanceled)
    18.         {
    19.             Debug.Log("Inner task was " + (task.IsFaulted ? "faulted." : "cancelled."));
    20.             return;
    21.         }
    22.  
    23.         // do initializations
    24.         // the results could as well be returned within a generic Task<T> in the
    25.         // continuation task, and bubble up through your method to the call site
    26.         _name = "Name that's in the database.";
    27.         return; // not necessary, no value to return since we do not use a generic task
    28.     });
    29. }
    As you can see, the task will be created by your method, but it doesn't want to do anything special after it's been completed... it only serves for the purpose of constructing the chain of tasks.
    On the other hand, Awake decides to immediately await the returned task... Awake could also just cache it and pass it somewhere else where it's then raised at any time, but you're free to handle this in any way you want.

    I assume though, that GetValueAsync of the FirebaseDatabasse is marked 'async', i.e. it's meant to be awaited, which leads us to the next solution:

    Code (CSharp):
    1. private string _name = null;
    2. private async void Awake()
    3. {
    4.     Debug.Log("before");
    5.  
    6.     await CopyInfoFromDB_Awaitable();
    7.  
    8.     Debug.Log("after");
    9.     Debug.Log(_name);
    10. }
    11.  
    12. public async Task CopyInfoFromDB_Awaitable() // note: an additional 'async' keyword
    13. {
    14.     // this requires 'async' in in front of the method's return type, as we want to await it within this method
    15.     await FirebaseDatabase.DefaultInstance.GetReference(path).GetValueAsync().ContinueWith(task =>
    16.     {
    17.         if (task.IsFaulted || task.IsCanceled)
    18.         {
    19.             Debug.Log("Inner task was " + (task.IsFaulted ? "faulted." : "cancelled."));
    20.             return;
    21.         }
    22.  
    23.         // do initializations
    24.         // the results could as well be returned within a generic Task<T> in the
    25.         // continuation task, and bubble up through your method to the call site
    26.         _name = "Name that's in the database.";
    27.         return; // not necessary, no value to return, since we do not use a geneic task
    28.     });
    29.  
    30.     // anything that you put here will be run once the awaiting above has finished
    31. }
    As you can see, Awake awaits the version of CopyInfoFromDB again, but this time, it's marked async and the implementation of that method itself awaits another task internally, which happens to be your async database access.

    This is just to get you started.
    If you read the commented parts carefully, you'll notice that you can change the way the tasks communicate with their callers.
    Instead of having the continuation fill the instance fields, you could switch to a return type of a generic task, and return the info that you've just read from the database, allowing the caller to pre-process everything.
    You could also return an indicator that tells the caller whether the task was successfull or not, making it easier to evaluate the current state for subsequent steps.

    That's all up to you.
     
    Last edited: Feb 8, 2019
  9. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    Thanks for your answer you are great!! I'm going to test it and write back when I'm done
     
  10. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    Suddoha so I followed your suggestion, it looks good, the only problem with that is that I must return a Task, so for example if I have a condition before the task that might be false- the function won't create a task at all, and then I'd have nothing to return. So maybe I should return some fake empty task to be able to use your code and skip the waiting? And the same thing when I use "try" for my task and it fails so I have to catch it and create an empty task to return because I have to return a task

    Code (CSharp):
    1. public async Task CopyInfoFromDB_Awaitable() // note: an additional 'async' keyword
    2. {  if (name.Equals("Tom"){
    3.     // this requires 'async' in in front of the method's return type, as we want to await it within this method
    4.     await FirebaseDatabase.DefaultInstance.GetReference(path).GetValueAsync().ContinueWith(task =>
    5.     {
    6.         if (task.IsFaulted || task.IsCanceled)
    7.         {
    8.             Debug.Log("Inner task was " + (task.IsFaulted ? "faulted." : "cancelled."));
    9.             return;
    10.         }
    11.         // do initializations
    12.         // the results could as well be returned within a generic Task<T> in the
    13.         // continuation task, and bubble up through your method to the call site
    14.         _name = "Name that's in the database.";
    15.         return; // not necessary, no value to return, since we do not use a geneic task
    16.     });
    17.     // nothing to return....
    18. }}
     
  11. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,257
    That only applies to one of the approaches, you have to distinguish the two scenarios I've demonstrated.

    The first one (not marked async) requires you to return an actual task object, whereas the second one (marked async) requires you to return anything that matches the task's result, except for the non-generic Task.

    That is, the return type of
    async Task
    only requires your async method to return, which happens implicity if you do not explicitly return (just as if you had a void method). However, when you use
    async Task<T>
    , you must either await another task of type Task<T> (or anything compatible to that), or a T if you do not await anything anymore.

    Code (csharp):
    1. Task Example1() { ...} // a normal method that returns a Task from its body (or anything that's assignable to Task)
    2. Task<T> Example2() { ... } // a normal method that returns Task<T> from its body (or anything that's assignable to Task<T>)
    3. async Task Example1Async() { ... } // an "async" method that simply returns from its body
    4. async Task<T> Example2Async() { ... } // an "async" method that must return a T (or anything that's assignable to T)
    The snippet you've chosen to work with uses 'async Task' as in Example1Async, so you should be able to return implicity or explicity. You're correct when you use simply return Tasks from non-async methods, as in Example1 - this one requires a Task to be returned. For cases in which you have no tasks to create and return, Task.CompletedTask was introduced with .Net 4.6. You can simply return that one instead.
     
  12. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    Hey Suddoha thanks for that, the reason why I chose the first approach is because I also use CallAsync task and I noticed that Firebase has this example-
    Code (CSharp):
    1. private Task<string> addMessage(string text) {
    2.   // Create the arguments to the callable function.
    3.   var data = new Dictionary<string, object>();
    4.   data["text"] = text;
    5.   data["push"] = true;
    6.  
    7.   // Call the function and extract the operation from the result.
    8.   var function = functions.GetHttpsCallable("addMessage");
    9.   return function.CallAsync(data).ContinueWith((task) => {
    10.     return (string) task.Result.Data;
    11.   });
    12. }
    But you are right- I need to use the second approach since I don't want to return anything back- the only problem is that I'll have to use "await" as you said -
    await function.CallAsync(data).ContinueWith((task) =>.......
    But then I'll get
    "Task does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'Task' could be found (are you missing a using directive or an assembly reference?)"

    I noticed that I can solve everything with coroutines (since I don't have to return values anyway) but I read that coroutines are not good for try and catch... I'm confused...
     
  13. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,257
    What's your project's player configuration? Have you included the required namespaces? Are you trying to use dynamics?

    *Edit Got it now, removed further explanations.

    Can you post the complete example that causes trouble?
     
    Last edited: Feb 12, 2019 at 8:10 AM
  14. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    Hey. What do you mean to include required namespaces? I get that error ""Task does not contain a definition for 'GetAwaiter'..." only with Callable tasks, here's my full example-
    Code (CSharp):
    1.  private async Task BuyItem(string text)
    2.     {
    3.         // Create the arguments to the callable function.
    4.         var data = new Dictionary<string, object>();
    5.         data["text"] = text;
    6.         data["push"] = true;
    7.  
    8.         // Call the function and extract the operation from the result.
    9.         var function = functions.GetHttpsCallable("buyItem");
    10.         await function.CallAsync(data).ContinueWith((task) => {
    11.             if (task.IsFaulted || task.IsCanceled)
    12.             {
    13.                 Debug.Log("");
    14.                 return;
    15.             }
    16.  
    17.             int money = (int)task.Result.Data;
    18.             userMoney = money;
    19.             return;
    20.         });
    21.     }
    As you can see in the picture, the minute I add "await"- everything becomes red.
    Note that it happens only with this type of Callable tasks (CallAsync),
    I have no problems adding "await" with regular tasks like the examples you gave me with GetValueAsync
     
  15. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,257
    That's weird. I checked their API and it definitely returns a task.

    I searched a bit via google and it's a common issue when you attempt to use tasks between .NET 4 and .NET 4.6, as the GetAwaiter stuff was introduced with 4.6. Additional installations are required to make it work prior to that.

    Now, the thing is that Unity probably does not use anything in between (can't tell for sure, I'm mainly sticking to .NET 3.5 because I have to for the current projects) and it used to show 4.x in the highest version that I have ever used - which basically says nothing but well, 4.0 or higher or another weirdly crafted "special" version.

    It also wouldn't make a hell lot of sense that it works with all tasks, except for those, unless you're using a rare mixture of assemblies that've been compiled against different versions.

    I'd definitely check that you're using the most recent stable releases of firebase, I have currently no other ideas and don't have lots of time to test things. However, you could upload a minimal project that re-produces the behaviour on your side, and upload it for me / others who want to fiddle with it.
     
  16. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
  17. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,257
    The errors wouldn't surprise me if you really use the .NET 3.5 version, as already mentioned earlier.

    Try to follow the 'known issues' section here, which covers the compatibility issues when using projects with another configuration. They talk about enabling and disabling the relevant assemblies for the corresponding versions. Not sure which implications that'll have on the usage and the API in general...
     
    Last edited: Feb 13, 2019 at 4:57 PM
  18. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    You were right, I updated .net and I don't get this error anymore.

    I started to use your code, but I noticed that there's a problem with nested awaits- it won't won't wait for the function to be completed. For example, running the following code will print

    -before
    -first task completed
    -Starting SendInfoToDatabase
    -after
    -name
    -Finishing SendInfoToDatabase

    But I want it to be:

    -before
    -first task completed
    -Starting SendInfoToDatabase
    -Finishing SendInfoToDatabase
    -after
    -name



    Code (CSharp):
    1. private string _name = null;
    2. private async void Awake()
    3. {
    4.     Debug.Log("before");
    5.     await CopyInfoFromDB_Awaitable();
    6.     Debug.Log("after");
    7.     Debug.Log(_name);
    8. }
    9. public async Task CopyInfoFromDB_Awaitable()
    10. {
    11.      await FirebaseDatabase.DefaultInstance.GetReference(path).GetValueAsync().ContinueWith(task =>
    12.     {
    13.         if (task.IsFaulted || task.IsCanceled)
    14.         {
    15.             Debug.Log("Inner task was " + (task.IsFaulted ? "faulted." : "cancelled."));
    16.             return;
    17.         }
    18.         // do initializations
    19.           _name = "Name that's in the database.";
    20.            Debug.Log("first task completed");
    21.        await SendInfoToDatabase();
    22.         return;
    23.     });
    24. }
    25. public async Task SendInfoToDatabase()
    26. {
    27.   Debug.Log("Starting SendInfoToDatabase");
    28.    await reference.SetValueAsync("done");
    29.    Debug.Log("Finishing SendInfoToDatabase");
    30. }
     
  19. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,257
    Well, now you've used another feature that you didn't use before, perhaps that wasn't your intention,

    First things first, was 'await SendInfoToDatabase' meant to be placed outside the continuation's lambda? In that case, you'd have your desired behaviour: The async query will be awaited and when it's finished, the rest of CopyInfo... will be run. That is, anything that follows can either be run synchronously, or it can be awaited.

    So ONE way to fix your issue the following (it's not perfect, as you obviously want to check the task's result):
    Code (CSharp):
    1. await FirebaseDatabase.DefaultInstance.GetReference(path).GetValueAsync().ContinueWith(task =>
    2. {
    3.     if (task.IsFaulted || task.IsCanceled)
    4.     {
    5.         Debug.Log("Inner task was " + (task.IsFaulted ? "faulted." : "cancelled."));
    6.         return;
    7.     }
    8.     // do initializations
    9.     _name = "Name that's in the database.";
    10.     Debug.Log("first task completed");
    11.     return;
    12. });
    13.  
    14. await SendInfoToDatabase();
    The second awaitable is now on the same level as the first awaitable, and they will be scheduled one after the other correctly, and both have to complete (or throw, in exceptional cases) before control is returned to the caller.

    As you may notice, the second one will always execute at the moment - you have to communicate the tasks and the queries result for further decision making.

    There are many ways to do that, here are a few of them:

    1) you could first get the task, save it locally in a variable of the tasks's type, then await it, and before you continue with the next awaitable, check its result - this might look ugly though

    2) You could use the actual result of the task and work with that after the task's completion, or use your own result that you specify as the return value of the continuation's function.

    3) You could save the result either in an instance variable of the wrapping type, or in a locally captured variable that you write to from within the continuation - that's just a lambda / delegate which captures everything that is used. You'd then work with those variables (or fields respectively) in order to determine whether you want to continue with SendInfoToDatabase. That's basically similar to 2), it simply works with variables / fields instead of returns values.

    4) Throw an exception that you handle on a level that's meant to care about that - you should only use this when it's really an exceptional behaviour (here's an excellent but short blog entry about basic exception "categories" - absolutely worth reading if you haven't yet).

    Let's head back to your latest snippet, and its execution behaviour:

    All the snippets prior to your latest version have a simple, "normal" continuation which is also solely meant to execute synchronously.
    That's sorta like a normal method, I mean, you could say it works like "when this task completes, do this sequence of commands and then return to the awaiting caller, no more async stuff".

    But you've changed the game a little a bit, as you start off another asynchronous call (btw - I'm not sure about later versions, but the continuation's lambda needs the 'async' keyword in order to be compilable, because you're using await inside).

    What this effectively does is, that you schedule a continuation for the task as before, but you also want a part of it to run asynchronously from within the continuation,.

    By default, this executes as follows:
    The outer task runs all of its instructions, when it completes, the continuation is triggered, i.e. it executes. However, if that continuation is marked 'async', the continuation will run synchronously until it hits the first await - it then returns control to the caller (that's the call sit of the continuation), and the outer task is then "complete", bubbles up, if there are more awaitables, those will be awaited, until it finally reaches the root of everything.

    In your particular example, the async firebase query runs, when the task's execution finishes (complete, cancelled, whatever) it triggers the continuation (ContinueWith) and that one runs synchronously - when it hits your asynchronous call to SetValueAsync, it'll start to await it, but then resumes immediately to CopyInfo... There's nothing to execute / await, so again it bubbles up to Awake and continues with that in the same way.

    Meanwhile, your newly started SetValueAsync keeps running detached from the original task, hence the incorrect order (technically it is correct).

    You can fix that, if you specifiy that the inner asynchronous call will be attached to its parent, as documented here (TaskContinuationOptions.AttachToParent).
     
    Last edited: Feb 17, 2019 at 1:55 PM
  20. shlighter

    shlighter

    Joined:
    Mar 2, 2017
    Posts:
    29
    Thanks for all that info!!
    Yes, I placed await SendInfoToDatabase inside the lambda because I was waiting for the task to be completed and use task.result, then continue with SendInfoToDatabase.

    Is TaskContinuationOptions.AttachToParent is another solution instead of 1 to 4 examples you gave?
    If so where do I use it? inside CopyInfoFromDB or inside SendInfoToDatabase,

    My main goal is that the functions shouldn't bubble up to parent until it's completely done, and finish all the inner "await" before returning to parent.

    I think I'll have to rewrite all tasks in my code and add "continue with" and TaskContinuationOptions.AttachToParent , because I have a lot of inner calls to different functions, and I want my code to finish the child functions before bubble up, even if there's await in a child task function it should finish with it before going back to a parent.

    I tried this code but still the same problem:

    Code (CSharp):
    1. private string _name = null;
    2. private async void Awake()
    3. {
    4.     Debug.Log("before");
    5.     await CopyInfoFromDB_Awaitable();
    6.     Debug.Log("after");
    7.     Debug.Log(_name);
    8. }
    9. public async Task CopyInfoFromDB_Awaitable()
    10. {
    11.      await FirebaseDatabase.DefaultInstance.GetReference(path).GetValueAsync().ContinueWith(async task =>
    12.     {
    13.         if (task.IsFaulted || task.IsCanceled)
    14.         {
    15.             Debug.Log("Inner task was " + (task.IsFaulted ? "faulted." : "cancelled."));
    16.             return;
    17.         }
    18.         // do initializations
    19.           _name = "Name that's in the database.";
    20.            Debug.Log("first task completed");
    21.        await SendInfoToDatabase();
    22.         return;
    23.     },TaskContinuationOptions.AttachedToParent);
    24. }
    25. public async Task SendInfoToDatabase()
    26. {
    27.   Debug.Log("Starting SendInfoToDatabase");
    28.    await reference.SetValueAsync("done").ContinueWith(task=> Debug.Log("done1") , TaskContinuationOptions.AttachedToParent );
    29.                 Debug.Log("After Done1");
    30.   await reference.SetValueAsync("done").ContinueWith(task=> Debug.Log("done2") , TaskContinuationOptions.AttachedToParent );
    31.   await reference.SetValueAsync("done").ContinueWith(task=> Debug.Log("done3") , TaskContinuationOptions.AttachedToParent );
    32.    Debug.Log("Finishing SendInfoToDatabase");
    33. }
    My code prints:
    -before
    -first task completed
    -Starting SendInfoToDatabase
    -done1
    -After Done1
    -after
    -name
    -done2
    -done3
    -Finishing SendInfoToDatabase
    But I need it to be- (before,first task completed, Starting SendInfoToDatabase,done1,after done1,done2,done3,Finishing SendInfoToDatabase,after, name)
     
    Last edited: Feb 17, 2019 at 10:02 PM