Using Async Without Await

Async function without await in JavaScript

Mozilla documentation:

An async function can contain an await expression, that pauses the
execution of the async function and waits for the passed Promise's
resolution, and then resumes the async function's execution and
returns the resolved value.

As you assumed, if no await is present, the execution is not paused and your code will then be executed synchronously as normal.

Is possible to call async function without await keyword? and what happens if we call without await?

We use await when we need to call and wait for async function or Promise
In your case when you call it without await inside your componentDidMount, your function will work but your componentDidMount will not wait for that function to completely finishes.

Also if you don't want to use await and you don't want to wait inside componentDidMount, but you want to get notified when your async function finishes, you can use .then instead. Because async functions returns Promise

Here is your componentDidMount with .then
Notice that in this example this.doSomethingElse will call before the this.usrs is complete, and you only will be notified inside .then about your this.usrs result when it finished:

componentDidMount(){
this.usrs(usrs).then(() => {
// Your functions completely finished
})
.catch(err => {
// There was an error
});

this.doSomethingElse();
}

How to call async function asynchronously without awaiting for the result

This behavior will change depending upon the context.

  • If you invoke this from a non-isolated context, then first and second will run on separate threads. In this scenario, the second task is not actually waiting for the first task, but rather there is a race as to which will finish first. This can be illustrated if you do something time-consuming in the first task and you will see the second task is not waiting at all.

    This introduces a race between first and second and you have no assurances as which order they will run. (In my tests, it runs second before first most of the time, but it can still occasionally run first before second.)

  • However, if you invoke this from an actor-isolated context, then first will wait for second to yield before running.

So, the question is, do you really care which order these two tasks start? If so, you can eliminate the race by (obviously) putting the Task { await first() } after the call to second. Or do you simply want to ensure that second won’t wait for first to finish? In that case, this already is the behavior and no change to your code is required.


You asked:

What if await first() needs to be run on the same queue as second() but asynchronously. … I am just thinking [that if it runs on background thread that it] would mean crashes due to updates of UI not from the main thread.

You can mark the routine to update the UI with @MainActor, which will cause it to run on the main thread. But note, do not use this qualifier with the time-consuming task, itself (because you do not want to block the main thread), but rather decouple the time-consuming operation from the UI update, and just mark the latter as @MainActor.

E.g., here is an example that manually calculates π asynchronously, and updates the UI when it is done:

func startCalculation() {
Task {
let pi = await calculatePi()
updateWithResults(pi)
}
updateThatCalculationIsUnderway() // this really should go before the Task to eliminate any races, but just to illustrate that this second routine really does not wait
}

// deliberately inefficient calculation of pi

func calculatePi() async -> Double {
await Task.detached {
var value: Double = 0
var denominator: Double = 1
var sign: Double = 1
var increment: Double = 0

repeat {
increment = 4 / denominator
value += sign * 4 / denominator
denominator += 2
sign *= -1
} while increment > 0.000000001

return value
}.value
}

func updateThatCalculationIsUnderway() {
statusLabel.text = "Calculating π"
}

@MainActor
func updateWithResults(_ value: Double) {
statusLabel.text = "Done"
resultLabel.text = formatter.string(for: value)
}

Note: To ensure this slow synchronous calculation of calculatePi is not run on the current actor (presumably the main actor), we want an “unstructured task”. Specifically, we want a “detached task”, i.e., one that is not run on the current actor. As the Unstructured Concurrency section of The Swift Programming Language: Concurrency: Tasks and Task Groups says:

To create an unstructured task that runs on the current actor, call the Task.init(priority:operation:) initializer. To create an unstructured task that’s not part of the current actor, known more specifically as a detached task, call the Task.detached(priority:operation:) class method.

C#: calling [async] method without [await] will not catch its thrown exception?

Within an async method, any exceptions are caught by the runtime and placed on the returned Task. If your code ignores the Task returned by an async method, then it will not observe those exceptions. Most tasks should be awaited at some point to observe their results (including exceptions).

The easiest solution is to make your Main asynchronous:

public static async Task Main(string[] args)
{
try
{
await ProcessAsync(null);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}

What is the best practice using async without await?

async is an implementation detail so you can remove it from the method if you are not using await, then you can use Task.FromResult to return an already completed task with the required result.

public class SynchronousViewDatabase : IDatabase
{
public Task<Data> GetData()
{
return Task.FromResult<Data>(GetData());
}
}

Are awaits in async method called without await still asynchronous?

Async methods always start running synchronously. The magic happens at await, but only when await is given a Task that has not completed.

In your example, this is what will happen when you call Run():

  1. Jump to DoStuffAsync()
  2. Jump to PerformCalc()
  3. Jump to DoLongTaskAsync()
  4. If DoLongTaskAsync() is a truly asynchronous operation and returns an incomplete Task, then await does its job and DoStuffAsync() returns an incomplete Task to Run().
  5. Since the task is not awaited, Run() completes.
  6. When DoLongTaskAsync() completes, DoStuffAsync() resumes, and jumps to PerformAnotherCalc().

All of that can happen on the same thread.

So to answer your questions:

  1. Yes. If it is an async method, it might end up going out and doing things on other threads. But it will start synchronously on the same thread.
  2. DoLongTaskAsync() will be called asynchronously, but PerformAnotherCalc() will not be called before DoLongTaskAsync() finishes, because you used await.
  3. Yes. This is how await works. It will return an incomplete Task (that is, only if DoLongTaskAsync() is truly asynchronous and returns an incomplete Task). Then once DoLongTaskAsync() finishes, execution of DoStuffAsync() resumes where it left off.


Related Topics



Leave a reply



Submit