Flutter Future vs Completer

守給你的承諾、 提交于 2020-12-31 04:45:49

问题


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.


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/57639378/flutter-future-vs-completer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!