有没有办法取消飞镖未来?

Ser*_*ahé 8 dart dart-async

在Dart UI中,我有一个按钮[submit]来启动长异步请求.[submit]处理程序返回Future.接下来,按钮[submit]被按钮[cancel]替换,以允许取消整个操作.在[取消]处理程序中,我想取消长操作.如何取消提交处理程序返回的Future?我发现没有办法做到这一点.

vov*_*ost 17

您可以使用CancelableOperationCancelableCompleter取消将来。请参阅以下2个版本:

解决方案1 ​​:(CancelableOperation包含在测试中,您可以自己尝试):

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

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

  // cancellableOperation.cancel();

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

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

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

  //  cancellableOperation.cancel();

  cancellableOperation.asStream().listen(
        (value) => { debugPrint('value: $value') },
        onDone: () => { debugPrint('onDone') },
      );
});
Run Code Online (Sandbox Code Playgroud)

以上两个测试将输出:

then: future result
onDone
Run Code Online (Sandbox Code Playgroud)

现在,如果我们取消注释,cancellableOperation.cancel();则以上两个测试将输出:

onCancel
Run Code Online (Sandbox Code Playgroud)

解决方案2 :(CancelableCompleter如果您需要更多控制权)

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

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

  // completer.operation.cancel();

  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'),
  });
});
Run Code Online (Sandbox Code Playgroud)

输出:

isCanceled: false
isCompleted: true
then: future result
onDone
Run Code Online (Sandbox Code Playgroud)

现在,如果我们取消注释,cancellableOperation.cancel();我们将得到输出:

onCancel
isCanceled: true
isCompleted: true
Run Code Online (Sandbox Code Playgroud)

请注意,如果使用await cancellableOperation.value或,await completer.operation则它将永远不会返回结果,并且如果操作被取消,它将无限期地等待。这是因为await cancellableOperation.value与写入相同,cancellableOperation.value.then(...)但是then()如果操作被取消则永远不会调用。

请记住添加异步 Dart程序包。

代码要点

  • 这个答案具有误导性。这些类不会取消 future 本身,而是创建可用于模仿取消行为的包装器 (15认同)
  • 关于异步的好点。这非常令人困惑,因为还有一个名为 async 的本机包 (3认同)
  • 感谢使用标准 dart 库,而不是发明自己的轮子。 (2认同)
  • 但这不是标准的 dart 库。这就是外部依赖。 (2认同)
  • 请注意,这不适用于延迟期货。这些是基于“Timer”的,并且不会保存内部计时器引用,因此一旦开始就无法阻止回调的执行。 (2认同)

And*_*eev 15

如何取消 Future.delayed

一个简单的方法是Timer改用:)

Timer _timer;

void _schedule() {
  _timer = Timer(Duration(seconds: 2), () { 
    print('Do something after delay');
  });
}

@override
void dispose() {
  super.dispose();
  _timer?.cancel();
}
Run Code Online (Sandbox Code Playgroud)

  • @iDecode您可以让“Timer”完成“Completer”,调用者可以“等待”“Completer”的“Future”。 (4认同)
  • 但你不能在 `Timer` 上 `await` :( (3认同)

Cop*_*oad 7

对于那些试图在 Flutter 中实现这一点的人,这里是相同的简单示例。

class MyPage extends StatelessWidget {
  final CancelableCompleter<bool> _completer = CancelableCompleter(onCancel: () => false);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Future")),
      body: Column(
        children: <Widget>[
          RaisedButton(
            child: Text("Submit"),
            onPressed: () async {
              // it is true only if the future got completed
              bool _isFutureCompleted = await _submit();
            },
          ),
          RaisedButton(child: Text("Cancel"), onPressed: _cancel),
        ],
      ),
    );
  }

  Future<bool> _submit() async {
    _completer.complete(Future.value(_solve()));
    return _completer.operation.value;
  }

  // This is just a simple method that will finish the future in 5 seconds
  Future<bool> _solve() async {
    return await Future.delayed(Duration(seconds: 5), () => true);
  }

  void _cancel() async {
    var value = await _completer.operation.cancel();
    // if we stopped the future, we get false
    assert(value == false);
  }
}
Run Code Online (Sandbox Code Playgroud)


Feu*_*Feu 6

我完成“取消”预定执行的一种方法是使用Timer. 在这种情况下,我实际上是在推迟它。:)

Timer _runJustOnceAtTheEnd;

void runMultipleTimes() {
  _runJustOnceAtTheEnd?.cancel();
  _runJustOnceAtTheEnd = null;

  // do your processing

  _runJustOnceAtTheEnd = Timer(Duration(seconds: 1), onceAtTheEndOfTheBatch);
}

void onceAtTheEndOfTheBatch() {
  print("just once at the end of a batch!");
}


runMultipleTimes();
runMultipleTimes();
runMultipleTimes();
runMultipleTimes();

// will print 'just once at the end of a batch' one second after last execution
Run Code Online (Sandbox Code Playgroud)

runMultipleTimes()方法将按顺序多次调用,但仅在批处理的 1 秒后onceAtTheEndOfTheBatch才会执行。

  • OP 询问的是取消 Future,而不是执行。 (2认同)

Rob*_*ton 6

我的2分钱值...

class CancelableFuture {
  bool cancelled = false;
  CancelableFuture(Duration duration, void Function() callback) {
    Future<void>.delayed(duration, () {
      if (!cancelled) {
        callback();
      }
    });
  }

  void cancel() {
    cancelled = true;
  }
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*uli 5

据我所知,没有办法取消未来。但是有一种取消Stream订阅的方法,也许可以为您提供帮助。

调用onSubmit按钮将返回一个StreamSubscription对象。您可以显式存储该对象,然后调用cancel()它以取消流订阅:

StreamSubscription subscription = someDOMElement.onSubmit.listen((data) {

   // you code here

   if (someCondition == true) {
     subscription.cancel();
   }
});
Run Code Online (Sandbox Code Playgroud)

稍后,作为对某些用户操作的响应,您可以取消订阅: