Skip to content

Instantly share code, notes, and snippets.

@PlugFox
Created February 27, 2025 01:39
Show Gist options
  • Save PlugFox/4ced7d394fb07ed329f8b69ea154dad1 to your computer and use it in GitHub Desktop.
Save PlugFox/4ced7d394fb07ed329f8b69ea154dad1 to your computer and use it in GitHub Desktop.
Go like defer in Dart
import 'dart:async' show Future, Zone, scheduleMicrotask;
final Object _deferredPushKey = Object();
/// Defers the given [callback] function to be executed after the current zone.
/// The callback will be executed in the reverse order of their registration.
void defer(void Function() callback) {
final push = Zone.current[_deferredPushKey];
if (push is void Function(void Function() callback)) {
push(callback);
} else {
throw StateError('defer() can only be called within runWithDefer()');
}
}
/// Runs the given [body] function in a new zone with deferred execution support.
T runWithDefer<T>(T Function() body, {bool microtask = false}) {
void Function()? stack;
void push(void Function() callback) {
final prev = stack;
stack = () {
try {
callback();
} finally {
prev?.call();
}
};
}
void execute() {
final call = stack;
if (call == null) {
return;
} else if (microtask) {
scheduleMicrotask(call);
} else {
call();
}
}
return Zone.current.fork(specification: null, zoneValues: <Object?, Object?>{_deferredPushKey: push}).run<T>(() {
var handled = false;
try {
final value = body();
assert(value is! Stream<Object?>, 'Stream is not supported by runWithDefer()');
if (value is Future<Object?>) {
handled = true;
return value..whenComplete(execute);
}
return value;
} on Object {
rethrow;
} finally {
if (!handled) execute();
}
});
}
import 'dart:async';
import 'defer.dart';
class Client {
Client() {
print('Client created');
}
Future<void> fetch(Object url) =>
Future.delayed(const Duration(milliseconds: 250), () => print('Client fetched $url'));
void close() => print('Client closed');
}
void main(List<String> arguments) => runWithDefer<void>(() async {
final client = Client();
defer(() => print('Program finished'));
defer(client.close);
await client.fetch('http://a.ru');
await client.fetch('https://b.com');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment