12

What is the difference between Future and Completer?

I am not looking for documentation part on either, instead I would like to see an example showing the real difference between the two.

  • A `Completer` *has* a `Future`. You'd use it to associate a `Future` with an asynchronous operation that doesn't provide a `Future` directly. Also see https://dart.dev/guides/language/effective-dart/usage#avoid-using-completer-directly – jamesdlin Aug 24 '19 at 16:13

2 Answers2

15

Completer is a helper class for creating Future whereas Future is a Type.

All asynchronous functions return Future, but with Completer it is possible to create synchronous function that returns Future as well. Also you can chain that synch functions with then etc.

Completer object is one way process, it's not restartable. It does the job and stops.

Future<MyObject> myMethod() {
  final completer = Completer();
  completer.complete(MyObject());
  return completer.future;
}

Update:

To give an example, in one of my projects I had to get the resolution info of network images. To do that, you need something like this: https://stackoverflow.com/a/44683714/10380182

In there, as you see, after getting the image we do a resolve process which may take time even though it's not an async process. To eliminate that blocking we simply use Completer.

Also the info we need exists inside a callback, so it will be cleaner to use Completer in there. Then, we use it via FutureBuilder. You can approach different but this is very convenient way to handle.

Mehmet Esen
  • 6,156
  • 3
  • 25
  • 44
  • Thanks, that was helpful, I'll wait before accepting it, may I know if `MyObject` is a `Future`? –  Aug 24 '19 at 16:36
  • `GetItemList() `is the Future, `MyObject` is the Type of the `Future`. So you can `MyObject myObject = await GetItemList();` – Daniel Eberl Aug 24 '19 at 16:39
  • @Volleyball MyObject is just an ordinary object. – Mehmet Esen Aug 24 '19 at 18:33
  • OK, I am accepting your answer but in case someone provides a better answer, I will accept theirs. Hope you don't mind that. Great day :) –  Aug 26 '19 at 07:15
  • 1
    @Volleyball no worries bro :) Time to time I'll update the answer better as much as I figure out more deeply the usecases. – Mehmet Esen Aug 26 '19 at 07:20
  • But what is the use case for 'myMethod?' why would anyone do that? What is the purpose? – Pete Alvin Jan 29 '20 at 12:26
10

Prefer Future over Completer

A Completer is a class that is used to create a Future from scratch. So unless you really are creating a Future from scratch you probably shouldn't be using a Completer.

How to make a Future

You can create a Future without using a Completer by using the Future's constructor:

final myFuture = Future(() {
  final result = doSomethingThatTakesTime();
  return result;
});

Using Future.then() is another way to get a Future:

Future<bool> fileContainsBear(String path) {
  return File(path).readAsString().then((contents) {
    return contents.contains('bear');
  });
}

And any async/await method returns a Future:

Future<bool> fileContainsBear(String path) async {
  var contents = await File(path).readAsString();
  return contents.contains('bear');
}

The above methods are all recommended over using a Completer:

// This is harder to read.
Future<bool> fileContainsBear(String path) {
  var completer = Completer<bool>();

  File(path).readAsString().then((contents) {
    completer.complete(contents.contains('bear'));
  });

  return completer.future;
}

How to make a Completer

But if you really do need to use a Completer, the way to do it is like this:

  1. Create a new Completer.
  2. Return its future.
  3. Tell the completer either when it is complete or when there is an error.

Here is an example:

class AsyncOperation {
  Completer _completer = new Completer();

  Future<T> doOperation() {
    _startOperation();
    return _completer.future; // Send future object back to client.
  }

  // Something calls this when the value is ready.
  void _finishOperation(T result) {
    _completer.complete(result);
  }

  // If something goes wrong, call this.
  void _errorHappened(error) {
    _completer.completeError(error);
  }
}

The code in this answer comes from the documentation and from the Effective Dart guide.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393