Dart Flutter, help me understand futures
Solution 1
Background
Asynchronous operations let your program complete work while waiting for another operation to finish. Here are some common asynchronous operations:
- Fetching data over a network.
- Writing to a database.
- Reading data from a file.
To perform asynchronous operations in Dart, you can use the Future class and the async and await keywords.
When an async function invokes "await", it is converted into a Future, and placed into the execution queue. When the awaited future is complete, the calling function is marked as ready for execution and it will be resumed at some later point. The important difference is that no Threads need to be paused in this model.
Futures vs async-await
When an async function invokes "await", it is converted into a Future, and placed into the execution queue. When the awaited future is complete, the calling function is marked as ready for execution and it will be resumed at some later point. The important difference is that no Threads need to be paused in this model.
async-await is just a a declarative way to define asynchronous functions and use their results into Future and it provides syntactic sugar that help you write clean code involving Futures.
Consider this dart code snipped involving Futures -
Future<String> getData(int number) {
return Future.delayed(Duration(seconds: 1), () {
return 'this is a future string $number.';
});
}
main(){
getData(10).then((data) => {
print(data)
});
}
As you can see when you use Futures, you can use then callback when the function return a future value. This is easy to manage if there is single "then" callback but the situation escalates quickly as soon as there are many nested "then" callbacks for example -
Future<String> getProductCostForUser() {
return getUser().then((user) => {
var uid = user.id;
return getOrder(uid).then((order) => {
var pid = order.productId;
return getProduct(pid).then((product) => {
return product.totalCost;
});
});
});
}
main(){
getProductCostForUser().then((cost) => {
print(cost);
});
}
As you can when there multiple chained "then" callback the code become very hard to read and manage. This problem is solved by "async-await". Above chained "then" callbacks can be simplified by using "async-await" like so -
Future<String> getProductCostForUser() async {
var user = await getUser();
var order = await getOrder(user.uid);
var product = await getProduct(order.productId);
return product.totalCost;
}
main() async {
var cost = await getProductCostForUser();
print(cost);
}
As you can above code is much more readable and easy to understand when there are chained "then" callbacks.
I hope this explains some basic concepts and understanding regarding the "async-await" and Futures.
You can further read about topic and examples here
Solution 2
Basically, you should either use await
OR then()
. However, Dart guidelines advocates that you should prefer use await
over then()
:
This code :
Future<int> countActivePlayers(String teamName) {
return downloadTeam(teamName).then((team) {
if (team == null) return Future.value(0);
return team.roster.then((players) {
return players.where((player) => player.isActive).length;
});
}).catchError((e) {
log.error(e);
return 0;
});
}
should be replaced by :
Future<int> countActivePlayers(String teamName) async {
try {
var team = await downloadTeam(teamName);
if (team == null) return 0;
var players = await team.roster;
return players.where((player) => player.isActive).length;
} catch (e) {
log.error(e);
return 0;
}
}
In your case, you should write :
void main(){
Future<String> someFunction() async {
SomeClass instance = SomeClass(); // creating object
String firstNameDeclaration = await instance.getData();
return firstNameDeclaration;
// Or directly : return await instance.getData();
// Or : return instance.getData();
}
}
Mehdi Rezzag Hebla
Updated on December 21, 2022Comments
-
Mehdi Rezzag Hebla over 1 year
See this code:
class SomeClass{ String someVariable; SomeClass(); Future<String> getData () async { Response response = await get('http://somewebsite.com/api/content'); Map map = jsonDecode(response.body); // do not worry about statuscode, trying to keep it minimal someVariable = map['firstName']; return 'This is the first name : $someVariable'; } }
Now look at main:
void main(){ String someFunction() async { SomeClass instance = SomeClass(); // creating object String firstNameDeclaration = await instance.getData().then((value) => value); return firstNameDeclaration; } }
When working with Future, like in the case of
firstNameDeclaration
why do I have to use.then()
method to access the string object, since I am waiting for the function to finish? When searching on the web, some people use.then()
others don't, I am confused.Kindly help me have a clearer understanding of how Futures and async functions overall work.
-
Augustin R almost 4 yearsYou should have a look to dart's guidelines about asynchrony
-
-
puelo almost 4 yearsSometimes it can be beneficial to mix both types. Since
then()
also returns aFuture
it can be used to operate on the result before assigning it to the variable (e.g.String body = await httpFuture.then((response) => response.body)
) -
Augustin R almost 4 yearsI get your point, however I would rather write
String body = (await httpFuture()).body;
-
puelo almost 4 yearsYeah you are right. I guess it comes down to personal preference in this case.
-
Mehdi Rezzag Hebla almost 4 yearsMuch appreciated, thank you for the elaborate and clear answer.
-
Python Steve over 3 yearsHow would someFunction() not produce a compile error? Doesn't a method have to return a Future<T> if the async keyword is used?