Why need to use Completer class

About the section Creating a Future From Scratch in Chapter 12 Futures, I just don’t understand why I need to use Completer class to build a Future instance.

The code using async keyword just work and very readable:

  Future<double> fetchTemperature(String city) async {
    if (city == 'Portland') {
      return 42.0;
    } else {
      return throw ArgumentError("$city doesn't exist.");
    }
  }

Compare the above for the code of Completer class:

@override
Future<double> fetchTemperature(String city) {
  final completer = Completer<double>();
  if (city == 'Portland') {
    completer.complete(42.0);
  } else {
    completer.completeError(ArgumentError("City doesn't exist."));
  }
  return completer.future;
}

1 Like

That’s a good question that the chapter in it’s current form doesn’t adequately answer. This deserves more explanation in the next edition or perhaps in an advanced Dart book.

For the contrived examples here, I agree that the async version is more readable. I would use async if I had to choose between the two.

A Completer is more useful for more complex requirements. One major use case is where you want to wrap a callback-based API in order to convert it to a Future-based API. Callbacks can be a little messy because you have to pass anonymous functions in as parameters. Converting such an API to a Future makes it a little easier to work with.

Let me refer you to a couple of articles as you continue your research:

Feel free to ask any followup questions after reading those. I may or may not be able to answer since this topic bumps up against the edge of my Dart knowledge (the only time I recall using a completer was when I tried to make an API for low-level database calls), but your questions will serve as markers for further research in the future. (no pun intended)

1 Like

@suragch thank you. I will take a look after finishing the book may be.