I was going over a lesson on async programming with Dart but for some reason I am getting kind of confused. I think I understand the concepts of how you should be using an async function when it may require some time and so instead of blocking and freezing your app you use an async function so that the next code blocks or methods are executed and when the async function is done or ready it executes. (Please let me know if my understanding is flawed)
However, I don't really get the Future<> part. I get it can be used as a return type of an async function because essentially you are saying the function returns a future object for now but let's come back to it when it's completed. But my instructor kind of confused me, sometimes she had a future as the return type and another time she didn't put it and they were both async functions. So now I'm struggling to understand when is it necessary to explicitly state the Future return type even if it is void? Also isn't just using async and wait for a function already create a future object regardless? Any clarification is greatly appreciated, thanks.
Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
Async methods can have the following return types: Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value. void , for an event handler.
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
Async functions The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically. So, async ensures that the function returns a promise, and wraps non-promises in it.
Let's consider a method gatherNewsReports()
which only returns a Future<String>
. The string value of the Future
from gatherNewsReports
. Implementation of gatherNewsReports
.
// Imagine this is a slow method. Takes time to finish
Future<String> gatherNewsReports() => Future.delayed(Duration(seconds: 1), () => news);
We will go through all possible combinations of method call with Future
and async
. The method I am going to make is called getDailyNewsDigest
One definition of the method might be as with Future
and async
given in method call:
Future<String> getDailyNewsDigest() async {
var str = await gatherNewsReports();
print(str);
return str;
}
Remember that gatherNewsReports()
which returns a Future<String>
. We are just returning whatever gatherNewsReports
returns.
Usage:
main() async {
await getDailyNewsDigest();
print('call done');
}
Output:
<gathered news goes here>
call done
Comments: This seems straight forward. You just call the method and await on it. Remember we are using await
keyword when calling getDailyNewsDigest
from the main
method. So, unless we pass 1 second
, i.e, the duration of time it requires the Future
to execute. If we didn't use the await keyword then the output sequence will be reversed.
One definition of the method might be as with Future
given and async
NOT given in method call:
Future<String> getDailyNewsDigest() {
var str = await gatherNewsReports();
print(str);
return str;
}
This is not valid because you can't call a method with await
, in this case gatherNewsReports
. This is invalid.
We define the method might be with Future
NOT GIVEN and async
given in method call. Since the return type is going to be void
we will not return anything (N.B: If we try to return anything other than a Future
or a void
then we get an error):
void getDailyNewsDigest() async {
var str = await gatherNewsReports();
print(str);
}
This is a valid method definition. Now, since the method is declared as void
we can't await
on the main
method. The updated main
method.
main() async {
getDailyNewsDigest(); // We can't await on it since return is void
print('call done');
}
Output:
call done
<gathered news goes here>
As you can see since the method getDailyNewsDigest
is not called without await
the output is reversed. We are no longer waiting for the getDailyNewsDigest
to finish.
We define the method might be with Future<Void>
instead of Future<String>
and async
given in method call:
Future<void> getDailyNewsDigest() async {
var str = await gatherNewsReports();
print(str);
return;
}
Now in our main method we can use the await
keyword again for calling getDailyNewsDigest
.
main() async {
await getDailyNewsDigest(); // We can await on it since return is Future<Void> but don't care on the output since it returns nothing
print('call done');
}
These are 4 combinations I can think of.
As for this:
But my instructor kind of confused me, sometimes she had a future as the return type and another time she didn't put it and they were both async functions.
Declaring a method with either Future
means you can await on it, declaring it with void
means you can't await
in it. You can of course choose not to await
on a Future
if you don't care to do anything with the output of the Future
. If you write your code in such a way that you don't want anyone to depend on the output of the method, i.e, the Future
we would otherwise return from the method will be handle d by itself, all we care about is firing-it-and-continue with our work; in that case we should define our method with return type void
.
Yes, using the async keyword will make the function automatically return a Future.
It is always better to explicitly declare the return type of a function even for void functions, if not, the compiler will interpret the function as having a dynamic return type.
It will also help/make it easier for the reader to know the return type of the function.
Also, you need to wrap your object in a Future in an async function like so:
Future<Object> getObject() async {
final object = await timeConsumingTask();
return object;
}
If you write it like this without wrapping it:
Object getObject() async {
final object = await timeConsumingTask();
return object;
}
The compiler throws the error: Functions marked 'async' must have a return type assignable to 'Future'.
For void functions, it seems that you do not have to wrap the return type in a Future, so something like this is fine:
void doSomething() async {
await timeConsumingTask();
print('done');
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With