Dart Flutter, help me understand futures

1,425

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();
  }
}
Share:
1,425
Mehdi Rezzag Hebla
Author by

Mehdi Rezzag Hebla

Updated on December 21, 2022

Comments

  • Mehdi Rezzag Hebla
    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
      Augustin R almost 4 years
      You should have a look to dart's guidelines about asynchrony
  • puelo
    puelo almost 4 years
    Sometimes it can be beneficial to mix both types. Since then() also returns a Future 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
    Augustin R almost 4 years
    I get your point, however I would rather write String body = (await httpFuture()).body;
  • puelo
    puelo almost 4 years
    Yeah you are right. I guess it comes down to personal preference in this case.
  • Mehdi Rezzag Hebla
    Mehdi Rezzag Hebla almost 4 years
    Much appreciated, thank you for the elaborate and clear answer.
  • Python Steve
    Python Steve over 3 years
    How would someFunction() not produce a compile error? Doesn't a method have to return a Future<T> if the async keyword is used?