Skip to content

Instantly share code, notes, and snippets.

@lrhn
Created July 24, 2020 11:34
Show Gist options
  • Save lrhn/5ede10df620fffb9c6c1c195f6349e83 to your computer and use it in GitHub Desktop.
Save lrhn/5ede10df620fffb9c6c1c195f6349e83 to your computer and use it in GitHub Desktop.
A cancelable zone which stops further async computations from running when it's cancelled
import "dart:async";
/// A cancelable zone.
///
/// A [Zone], and a [cancel] function which makes the zone stop processing events.
/// After calling [cancel], the zone's timers, microtasks and `run` methods
/// ([Zone.run], [Zone.runUnary] and [Zone.runBinary]) stop doing anything.
/// Calling the `run` methods will throw, and any scheduled timers or
/// microtasks will do nothing instead of calling the configured callback.
class CancelableZone {
final Zone zone;
void Function() _cancel;
void cancel() { _cancel(); }
CancelableZone._(this.zone, this._cancel);
factory CancelableZone([void onError(Object error, StackTrace stack)?]) {
bool isCanceled = false;
void cancel() {
isCanceled = true;
}
var parent = Zone.current;
var zone = parent.fork(specification: ZoneSpecification(
run: <R>(s, p, z, f) {
if (!isCanceled) return p.run<R>(z, f);
throw CancelledException();
},
runUnary: <R, T>(s, p, z, f, a) {
if (!isCanceled) return p.runUnary<R, T>(z, f, a);
throw CancelledException();
},
runBinary: <R, T, S>(s, p, z, f, a, b) {
if (!isCanceled) return p.runBinary<R, T, S>(z, f, a, b);
throw CancelledException();
},
scheduleMicrotask: (s, p, z, m) {
if (isCanceled) return;
p.scheduleMicrotask(parent, () {
if (!isCanceled) p.run(z, m);
else throw CancelledException();
});
},
createTimer: (s, p, z, d, f) {
var timer = p.createTimer(parent, d, () {
if (!isCanceled) p.run(z, f);
});
if (isCanceled) timer.cancel();
return timer;
},
createPeriodicTimer: (s, p, z, d, f) {
var timer = p.createPeriodicTimer(parent, d, (t) {
if (!isCanceled) {
p.runUnary(z, f, t);
} else {
t.cancel();
}
});
if (isCanceled) timer.cancel();
return timer;
},
handleUncaughtError: onError == null ? null :
(s, p, z, e, st) => p.runBinary(z, onError, e, st)
));
return CancelableZone._(zone, cancel);
}
}
class CancelledException implements Exception {
CancelledException();
String toString() => "CancelledException";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment