submit
的按钮,用于启动一个长时间异步请求。该submit
处理程序返回一个Future。接下来,将submit
按钮替换为cancel
按钮,以允许取消整个操作。在cancel
处理程序中,我想要取消由submit
处理程序返回的长时间操作。但我找不到可以这样做的方法。submit
的按钮,用于启动一个长时间异步请求。该submit
处理程序返回一个Future。接下来,将submit
按钮替换为cancel
按钮,以允许取消整个操作。在cancel
处理程序中,我想要取消由submit
处理程序返回的长时间操作。但我找不到可以这样做的方法。您可以使用CancelableOperation或CancelableCompleter来取消一个Future。以下是这2个版本:
CancelableOperation
(包括测试,您可以自己尝试):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'),
});
});
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') },
);
});
两个测试的输出结果都将是:
then: future result
onDone
如果我们取消注释 cancellableOperation.cancel();
,那么上述两个测试都将输出:
onCancel
CancelableCompleter
(如果您需要更多控制)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'),
});
});
输出:
isCanceled: false
isCompleted: true
then: future result
onDone
现在,如果我们取消注释cancellableOperation.cancel();
,我们将得到以下输出:
onCancel
isCanceled: true
isCompleted: true
注意,如果您使用 await cancellableOperation.value
或 await completer.operation
,则该 future 将永远不会返回结果,并且如果操作被取消,则它将无限期地等待。这是因为 await cancellableOperation.value
相当于编写 cancellableOperation.value.then(...)
但是如果操作被取消,then()
将永远不会被调用。
Future.delayed
一个简单的方法是使用 Timer
替代 :)
Timer _timer;
void _schedule() {
_timer = Timer(Duration(seconds: 2), () {
print('Do something after delay');
});
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
Timer
上使用 await
:( - iDecodeonSubmit
将返回一个StreamSubscription
对象。您可以显式存储该对象,然后调用cancel()
以取消流订阅:StreamSubscription subscription = someDOMElement.onSubmit.listen((data) {
// you code here
if (someCondition == true) {
subscription.cancel();
}
});
后来,作为对某些用户操作的响应,您可以取消订阅:
我实现“取消”定时执行的一种方法是使用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
runMultipleTimes()
方法将会按顺序被多次调用,但是只有在批处理的最后1秒时才会执行onceAtTheEndOfTheBatch
。
对于那些想在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);
}
}
以下是我的个人意见...
class CancelableFuture {
bool cancelled = false;
CancelableFuture(Duration duration, void Function() callback) {
Future<void>.delayed(duration, () {
if (!cancelled) {
callback();
}
});
}
void cancel() {
cancelled = true;
}
}
CancelableOperation
并不会阻止未来的回调执行,而答案则可以。尝试取消一个 Future.delayed(...)
,它仍然会执行 --- CancelableOperation.fromFuture(Future.delayed(Duration(seconds: 1), () => print("Finished 1")), onCancel: () => print("Cancelled"),).cancel()
- gegCancelableCompleter
)。 - mr_mmmmore现在,您可以使用CancelableOperation来实现此操作,该类位于pub.dev的async包中。请注意,不要将这个包混淆与内置的dart核心库dart:async
,因为后者没有这个类。
您可以使用timeout()方法
创建一个虚拟的future:
Future<String?> _myFuture() async {
await Future.delayed(const Duration(seconds: 10));
return 'Future completed';
}
设置3秒超时,以便在10秒之前提前停止:
_myFuture().timeout(
const Duration(seconds: 3),
onTimeout: () =>
'The process took too much time to finish. Please try again later',
);
就是这样,你取消了你的未来。
`Future f = new Future.delayed(new Duration(seconds: 2), () => print('2 secs passed'));
f.timeout(const Duration(seconds: 0), onTimeout: () { print ('timed out'); });`
打印`timed out
2 secs passed`
。使用catchError捕获超时或提供onTimeout参数都没有任何区别。future总是运行。 - Gazihan Alankus这个解决方案类似于一个可等待的计时器
或者一个可取消的Future.delayed
,它既像计时器
一样可取消,又像Future
一样可等待。
它基于一个非常简单的类,CancelableCompleter
,下面是一个演示:
import 'dart:async';
void main() async {
print('start');
// Create a completer that completes after 2 seconds…
final completer = CancelableCompleter.auto(Duration(seconds: 2));
// … but schedule the cancelation after 1 second
Future.delayed(Duration(seconds: 1), completer.cancel);
// We want to await the result
final result = await completer.future;
print(result ? 'completed' : 'canceled');
print('done');
// OUTPUT:
// start
// canceled
// done
}
现在是该类的代码:
class CancelableCompleter {
CancelableCompleter.auto(Duration delay) : _completer = Completer() {
_timer = Timer(delay, _complete);
}
final Completer<bool> _completer;
late final Timer? _timer;
bool _isCompleted = false;
bool _isCanceled = false;
Future<bool> get future => _completer.future;
void cancel() {
if (!_isCompleted && !_isCanceled) {
_timer?.cancel();
_isCanceled = true;
_completer.complete(false);
}
}
void _complete() {
if (!_isCompleted && !_isCanceled) {
_isCompleted = true;
_completer.complete(true);
}
}
}
更完整的类运行示例可在this DartPad中找到。