-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Future#cancel #1806
Comments
Siggi, this is your area. cc @kasperl. |
This comment was originally written by @seaneagan A couple of use cases for this: I believe the only reason for the Timer class to exist now is that a Future.delayed(...) callback cannot be canceled. and the only reason for dart:html.requestAnimationFrame to exist is that a dart:html.animationFrame callback cannot be canceled. However, I think the API for cancellation should look similar to how it does for Streams, where the callback subscription method returns an object which can be used to cancel the callback. It would probably look just like Future.then, except return such an object: Canceler maybe(onValue(T value), {onError(AsyncError asyncError)}); where dart:async defines: typedef void Canceler(); |
+florian who's now actively maintaining this code. cc @floitschG. |
cc @lrhn. |
I don't like this proposal, for a couple reasons. From a semantic standpoint, I think Futures work best when they're consistently thought of as a way of declaring a chain of computations, rather than registering callbacks on an emitter, which is more of a Stream thing. A cancelable callback goes against this idea. From a more pragmatic angle, I've found it to be useful in various cases to create classes that implement Future, and adding more methods to it makes these classes harder to write. Why not just use future.asStream().listen and get all the benefits of the StreamSubscription API? |
This comment was originally written by @seaneagan It seems to make just as much sense to be able to cancel It seems like implementing extra methods on Future should be handled That workaround works, but it's not quite as convenient or discoverable: future.asStream().listen(callback) vs: future.maybe(callback); I can't think of any reason to "pause" / "resume" a Future subscription, but there probably are some out there. |
Listeners on futures are not "subscribers". A utility function doing what you want would be: class Canceler {
bool _canceled = false;
Canceler(this.result);
final Future result;
void cancel() { _canceled = true; }
}
Canceler maybe(Future future, continuation(var result), {onError(error)}) {
Canceler canceler;
Completer completer = new Completer();
Future future = future.then((v) {
if (!canceler._canceled) {
return continuation(v);
} else {
return new Completer().future; // Never completes.
}
}, onError: (e) {
if (!canceler._canceled) {
if (onError != null) return onError(e);
throw e;
}
return new Completer().future;
});
canceler = new Canceler(future);
return canceler;
} (Obviously not tested!) I don't think we want subscriptions on futures. |
We have no current plans to add canceling to futures, or to allow removing then-handlers from futures. Removed Type-Defect label. |
@kwalrath This is the cancel future ticket. |
@lrhn in a chat with developers today, one said that having lots of "open" futures slows down apps and is hard to diagnose. Do we have any plans to revisit this, or are there tools devs can use to hunt down these futures and fix their code? |
There is no cost to having an "open" future that doesn't do computation. It's just an object, like any other object. We can help you write such functions. I still recommend using import "dart:async";
import "package:async/async.dart";
CancelableOperation<T> runWithCancel<T>(
Future<T> action(Future<void> onCancel)) {
var cancel = Completer<void>();
return CancelableOperation<T>.fromFuture(action(cancel.future), onCancel: () {
cancel.complete();
return null;
});
}
main() {
var running = runWithCancel<int>((cancelFuture) async {
bool isCancelled = false;
cancelFuture.then((_) {
isCancelled = true;
});
int i = 0;
while (true) {
if (isCancelled) return -1;
print(i++);
await Future.delayed(Duration(milliseconds: 250));
}
return 42;
});
var timer = Timer(Duration(seconds: 2), running.cancel);
running.value.then(print).whenComplete(timer.cancel);
} We still have no current plans to add |
As a Dart user, I think there may be a situation where a cancelable future is very useful. When using
When a Stream from Allowing such syntax will also make
But |
@pinyin For what it's worth, you can write: Stream<int> load10Data(CancelableOperation<int> loadAt(int index)) async* {
for (var i = 0; i < 10; i++) {
yield* loadAt(i).asStream();
}
} and it should have the behavior you want when you cancel the |
Your example of If it completes with a value, then computation will continue with that value. If you have One alternative is to make it throw an var res = await allocateResource();
try {
. ..
} finally {
res.dispose();
} (which is perfectly good If any The only semantically reasonable option is to make a cancelled future never complete. Sadly, that's too dangerous to allow. If the future never completes, the method body is stuck at the var res = allocateResource();
try {
while (await res.fetchNextPage()) {
for (var entry in res.currentPage) yield entry;
}
} finally {
await res.dispose();
} Now, if this This is all an aside from cancelable futures, saying why even if we had them, an All in all, we are not planing to make futures cancelable. The API is all wrong for that. |
Thanks for the replies & clear explanations.
may still exist. |
Revisions updated by `dart tools/rev_sdk_deps.dart`. dartdoc (https://github.com/dart-lang/dartdoc/compare/dc502d0..4d7dc93): 4d7dc93b 2022-12-05 dependabot[bot] Bump github/codeql-action from 2.1.31 to 2.1.35 (#3263) bcf8b6e8 2022-12-05 Parker Lougheed Weight enums the same as classes for searching (#3260) 7d95578b 2022-12-04 Parker Lougheed Update template descriptions (#3258) d558f043 2022-12-04 Parker Lougheed Fix error when using base element href (#3256) c3663762 2022-12-04 Parker Lougheed Add unnecessary override ignore to fix build (#3257) http (https://github.com/dart-lang/http/compare/976bd56..46a7708): 46a7708 2022-12-02 Brian Quinlan Remove binary artifact (#833) sync_http (https://github.com/dart-lang/sync_http/compare/f5c1f18..8622614): 8622614 2022-12-02 Kevin Moore blast_repo fixes (#32) test (https://github.com/dart-lang/test/compare/f3d80a6..4dceb87): 4dceb87c 2022-12-01 Nate Bosch Ignore some usage of dperecated errors (#1807) webdev (https://github.com/dart-lang/webdev/compare/91b8a19..e39506e): e39506e 2022-12-05 Anna Gringauze Pre-warm expression compiler to speed up Flutter Inspector page loading. (#1786) 9b19b3b 2022-12-02 Elliott Brooks (she/her) Can save storage objects in both `session` and `local` storage (#1807) e75c45e 2022-12-02 Elliott Brooks (she/her) Injected client adds `isFlutterApp` to global window object (#1806) ba5e3ec 2022-12-01 Elliott Brooks (she/her) `DebugSession` listens to events instead of just sending events (#1804) Change-Id: I881d02e966b763879df72b29653a9f241b71eb3d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/273826 Commit-Queue: Devon Carew <devoncarew@google.com> Reviewed-by: Nate Bosch <nbosch@google.com>
Revisions updated by `dart tools/rev_sdk_deps.dart`. dartdoc (https://github.com/dart-lang/dartdoc/compare/4d7dc93..f2bb6e9): f2bb6e92 2022-12-07 Sam Rawlins Bump to 6.1.4 (#3266) fixnum (https://github.com/dart-lang/fixnum/compare/62916f2..e4f5e97): e4f5e97 2022-12-08 Michael Thomsen Change IntegerDivisionByZeroException to UnsupportedError (#100) 3bd726f 2022-12-08 Devon Carew rev the sdk min to 2.19.0-0 (#99) logging (https://github.com/dart-lang/logging/compare/f322480..0373ef8): 0373ef8 2022-12-07 Mushaheed Syed Add a check that throws if a logger name ends with '.' (#123) 6d46d71 2022-12-06 Devon Carew Create no-response.yml (#124) protobuf (https://github.com/dart-lang/protobuf/compare/4f3e328..2706b53): 2706b53 2022-12-07 Mahdi K. Fard Add type to a method parameter (#782) a57c16a 2022-12-07 Mahdi K. Fard Fix a typo (#781) shelf (https://github.com/dart-lang/shelf/compare/1c21047..32e342d): 32e342d 2022-12-08 István Soós Prepare the release of shelf_router_generator (#316) 06e2fe6 2022-12-08 Kevin Moore shelf: drop non-null-safe tests (#317) 98363fd 2022-12-06 Kevin Moore lint: sort pub dependencies ad6af2a 2022-12-06 Kevin Moore shelf_static: move RegExp creation out of every request test (https://github.com/dart-lang/test/compare/4dceb87..73cd754): 73cd7540 2022-12-07 Nate Bosch Record the working directory for VM platform (#1804) e40274a6 2022-12-07 Nate Bosch Restore mono_repo config (#1810) 02d8764e 2022-12-07 Sigurd Meldgaard Use Future for return type in runner `main()`. (#1809) 3d6039b3 2022-12-05 Nate Bosch Merge test selections by path (#1806) webdev (https://github.com/dart-lang/webdev/compare/e39506e..3e2364e): 3e2364e 2022-12-07 Elliott Brooks (she/her) Add the Dart Debugger / Flutter Inspector panels in Chrome DevTools (#1812) c164231 2022-12-07 Elliott Brooks (she/her) Small fix to the extension test (#1811) 4bbb4d0 2022-12-06 Elliott Brooks (she/her) Gracefully handle debugger disconnect events (#1808) d3892cf 2022-12-05 Elliott Brooks (she/her) Refactor puppeteer tests to use `Worker` type (#1809) Change-Id: I42033e849f40f209831cfb344247b24ad7731ff0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274580 Reviewed-by: Nate Bosch <nbosch@google.com> Commit-Queue: Devon Carew <devoncarew@google.com>
This issue was originally filed by @seaneagan
Future should allow canceling of callbacks added with Future#then. Might look like:
void cancel(void onComplete(T value));
example:
future.then(onComplete);
//...
future.cancel(onComplete);
The text was updated successfully, but these errors were encountered: