7

Lets say I have a function A that uses a function B which uses C, etc:

A -> B -> C -> D and E

Now assume that function D has to use async/await. This means I have to use async/await to the call of function C and then to the call of function B and so on. I understand that this is because they depend on each other and if one of them is waiting for a function to resolve, then transitively, they all have to. What alternatives can I do to make this cleaner?

ninesalt
  • 4,054
  • 5
  • 35
  • 75
  • You can't do that. – SLaks Jan 27 '19 at 13:47
  • Maybe you can find some helpful advice in [this answer](https://stackoverflow.com/a/45448272/1048572) – Bergi Jan 27 '19 at 13:51
  • You can't. Asynchronicity is viral. An alternative is to stick to synchronous alternatives for things that can be done both ways (`fs`, etc), which is rarely a good idea. – Estus Flask Jan 27 '19 at 14:21
  • You can always call `D` in `C` without awaiting it but rather with attaching a continuation with `then`. This way async doesn't bubble. This only works if the result is not nedded up the chain, though. – Wiktor Zychla Jan 27 '19 at 14:40
  • @WiktorZychla Syntax doesn't matter, the OP's point seems to be that the functions all return a promise. – Bergi Jan 27 '19 at 14:59

1 Answers1

3

There is a way to do this, but you'll loose the benefits of async-await.

One of the reason for async-await, is, that if your thread has to wait for another process to complete, like a read or write to the hard-disk, a database query, or fetching some internet information, your thread might do some other useful stuff instead of just waiting idly for this other process to complete.

This is done by using the keyword await. Once your thread sees the await. The thread doesn't really wait idly. Instead, it remembers the context (think of variable values, parts of the call stack etc) and goes up the call stack to see if the caller is not awaiting. If not, it starts executing these statements until it sees an await. It goes up the call stack again to see if the caller is not awaiting, etc.

Once this other process is completed the thread (or maybe another thread from the thread pool that acts as if it is the original thread) continues with the statements after the await until the procedure is finished, or until it sees another await.

To be able to do this, your procedure must know, that when it sees an await, the context needs to be saved and the thread must act like described above. That is why you declare a method async.

That is why typical async functions are functions that order other processes to do something lengthy: disk access, database access, internet communications. Those are typical functions where you'll find a ReadAsync / WriteAsync, next to the standard Read / Write functions. You'll also find them in classes that are typically designed to call these processes, like StreamReaders, TextWriters etc.

If you have a non-async class that calls an async function and waits until the async function completes before returning, the go-up-the-call-stack-to-see-if-the-caller-is-not-awaiting stops here: your program acts as if it is not using async-await.

Almost!

If you start an awaitable task, without waiting for it to finish, and do something else before you wait for the result, then this something else is executed instead of the idly wait, that the thread would have done if you would have used the non-async version.

How to call async function from non-async function

ICollection<string> ReadData(...)
{
     // call the async function, don't await yet, you'll have far more interesting things to do
     var taskReadLines = myReader.ReadLinesAsync(...);

     DoSomethingInteresting();

     // now you need the data from the read task. 
     // However, because this method is not async, you can't await.
     // This Wait will really be an idle wait.
     taskReadLines.Wait();
     ICollection<string> readLines= taskRead.Result;
     return readLines();
}

Your callers won't benefit from async-await, however your thread will be able to do something interesting while the lines have not been read yet.

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • You don't show enough code to reproducible the solution. :( If ReadLinesAsync() is an async function, that means it's returning a Promise, right? But the Promise object doesn't have a Wait() method, nor does it have a Result property. I'd love for something like your code to work, but you really need to give more details. – kbrannen Jun 14 '23 at 16:55