Created
July 24, 2020 11:34
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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