Last active
May 29, 2025 17:36
-
-
Save ivanboltyshev/7da431278887fa92c1801070e1af931a to your computer and use it in GitHub Desktop.
This utility provides a lightweight cancellation mechanism in Dart, similar to Kotlin’s Job and coroutine cancellation.
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
class CancellableTask { | |
StreamController<void>? _cancelController; | |
bool _isCancelled = false; | |
bool get isCancelled => _isCancelled; | |
void cancel() { | |
if (_isCancelled) return; | |
_isCancelled = true; | |
if (!(_cancelController?.isClosed ?? true)) { | |
_cancelController?.add(null); | |
_cancelController?.close(); | |
} | |
} | |
Future<void> launch(Future<void> Function(CancellableTaskContext context) task) async { | |
cancel(); | |
_isCancelled = false; | |
_cancelController = StreamController<void>.broadcast(); | |
final context = CancellableTaskContext._( | |
cancelStream: _cancelController!.stream, | |
isCancelled: () => _isCancelled, | |
); | |
try { | |
await task(context); | |
} catch (e, st) { | |
if (_isCancelled) { | |
print('[CancellableTask] Cancelled'); | |
} else { | |
rethrow; | |
} | |
} finally { | |
await _cancelController?.close(); | |
} | |
} | |
} |
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
class CancellableTaskContext { | |
CancellableTaskContext._({ | |
required Stream<void> cancelStream, | |
required bool Function() isCancelled, | |
}) : _cancelStream = cancelStream, | |
_isCancelledFn = isCancelled; | |
final Stream<void> _cancelStream; | |
final bool Function() _isCancelledFn; | |
bool get isCancelled => _isCancelledFn(); | |
Future<void> delay(Duration duration) async { | |
if (isCancelled) return; | |
final completer = Completer<void>(); | |
final timer = Timer(duration, completer.complete); | |
final sub = _cancelStream.listen((_) { | |
if (!completer.isCompleted) { | |
timer.cancel(); | |
completer.completeError(Exception('Cancelled')); | |
} | |
}); | |
try { | |
await completer.future; | |
} finally { | |
await sub.cancel(); | |
} | |
} | |
void checkCancelled() { | |
if (isCancelled) throw Exception('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
class ClassExample { | |
CancellableTask? _task; | |
Future<void> call() async { | |
_task?.cancel(); | |
_task = CancellableTask(); | |
await _task?.launch((context) async { | |
await _jobOne(); | |
await context.delay(const Duration(milliseconds: 2000)); | |
await _jobTwo(); | |
await context.delay(const Duration(milliseconds: 2000)); | |
await _jobThree(); | |
}); | |
} | |
Future<void> _jobOne() async { | |
await Future.delayed(const Duration(milliseconds: 2000)); | |
} | |
Future<void> _jobTwo() async { | |
await Future.delayed(const Duration(milliseconds: 2000)); | |
} | |
Future<void> _jobThree() async { | |
await Future.delayed(const Duration(milliseconds: 2000)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
CancellableTask — Kotlin-style Job cancellation in Dart
This utility provides a lightweight cancellation mechanism in Dart, similar to Kotlin’s Job and coroutine cancellation.
It allows you to:
• Execute a sequence of asynchronous operations as a single cancellable task.
• Cancel the entire operation chain at any moment with cancel().
• Automatically stop long-running steps like Future.delayed using context.delay(...).
• Check for cancellation manually using context.checkCancelled().
Problem it solves
Dart Futures cannot be cancelled once started. This utility provides a structured way to manage cancellable async flows — something Dart lacks out of the box, but is essential for user-driven workflows like voice playback, animations, and data loading where users can interrupt operations at any time.