Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.6k views
in Technique[技术] by (71.8m points)

is there any way to cancel a dart Future?

In a Dart UI, I have a button [submit] to launch a long async request. The [submit] handler returns a Future. Next, the button [submit] is replaced by a button [cancel] to allow the cancellation of the whole operation. In the [cancel] handler, I would like to cancel the long operation. How can I cancel the Future returned by the submit handler? I found no method to do that.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can use CancelableOperation or CancelableCompleter to cancel a future. See below the 2 versions:

Solution 1: CancelableOperation (included in a test so you can try it yourself):

  • cancel a future

test("CancelableOperation with future", () async {

  var cancellableOperation = CancelableOperation.fromFuture(
    Future.value('future result'),
    onCancel: () => {debugPrint('onCancel')},
  );

// cancellableOperation.cancel();  // uncomment this to test cancellation

  cancellableOperation.value.then((value) => {
    debugPrint('then: $value'),
  });
  cancellableOperation.value.whenComplete(() => {
    debugPrint('onDone'),
  });
});
  • cancel a stream

test("CancelableOperation with stream", () async {

  var cancellableOperation = CancelableOperation.fromFuture(
    Future.value('future result'),
    onCancel: () => {debugPrint('onCancel')},
  );

  //  cancellableOperation.cancel();  // uncomment this to test cancellation

  cancellableOperation.asStream().listen(
        (value) => { debugPrint('value: $value') },
    onDone: () => { debugPrint('onDone') },
  );
});

Both above tests will output:

then: future result
onDone

Now if we uncomment the cancellableOperation.cancel(); then both above tests will output:

onCancel

Solution 2: CancelableCompleter (if you need more control)

test("CancelableCompleter is cancelled", () async {

  CancelableCompleter completer = CancelableCompleter(onCancel: () {
    print('onCancel');
  });

  // completer.operation.cancel();  // uncomment this to test cancellation

  completer.complete(Future.value('future result'));
  print('isCanceled: ${completer.isCanceled}');
  print('isCompleted: ${completer.isCompleted}');
  completer.operation.value.then((value) => {
    print('then: $value'),
  });
  completer.operation.value.whenComplete(() => {
    print('onDone'),
  });
});

Output:

isCanceled: false
isCompleted: true
then: future result
onDone

Now if we uncomment the cancellableOperation.cancel(); we get output:

onCancel
isCanceled: true
isCompleted: true

Be aware that if you use await cancellableOperation.value or await completer.operation then the future will never return a result and it will await indefinitely if the operation was cancelled. This is because await cancellableOperation.value is the same as writing cancellableOperation.value.then(...) but then() will never be called if the operation was cancelled.

Remember to add async Dart package.

Code gist


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...