Skip to content

Instantly share code, notes, and snippets.

@iota9star
Last active October 8, 2022 08:19
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iota9star/06e53530f75de974b4aeb7dc0c0ab3ea to your computer and use it in GitHub Desktop.
Save iota9star/06e53530f75de974b4aeb7dc0c0ab3ea to your computer and use it in GitHub Desktop.
import 'dart:async';
import 'dart:collection';
Future<void> main() async {
final list = await [
Future.delayed(const Duration(milliseconds: 1500), () => 1),
Future.delayed(const Duration(milliseconds: 5000), () => throw '2'),
Future.delayed(const Duration(milliseconds: 1200), () => 3),
Future.delayed(const Duration(milliseconds: 8000), () => throw '4'),
Future.delayed(const Duration(milliseconds: 4300), () => 5),
Future.delayed(const Duration(milliseconds: 3000), () => 6),
Future.delayed(const Duration(milliseconds: 7000), () => 6),
Future.delayed(const Duration(milliseconds: 3000), () => 7),
Future.delayed(const Duration(milliseconds: 4000), () => 8),
Future.delayed(const Duration(milliseconds: 3000), () => 9),
Future.delayed(const Duration(milliseconds: 6000), () => 10),
].allSettled(
parallel: 2,
onSuccess: (index, value) {
print('index: $index, value: $value');
},
onError: (index, e, s) {
print('index: $index, error: $e');
},
);
print(list);
}
extension IterableFuture<T> on Iterable<Future<T>> {
Future<List<FutureResult<T>>> allSettled({
int parallel = 0,
void Function(int index, T value)? onSuccess,
void Function(int index, Object error, StackTrace stackTrace)? onError,
void Function(
int index,
FutureResultStatus status,
T? value,
Object? error,
StackTrace? stackTrace,
)?
onComplete,
}) {
final len = length;
if (len == 0) {
return Future.value(<FutureResult<T>>[]);
}
final completer = Completer<List<FutureResult<T>>>();
int remaining = len;
final list = List<FutureResult<T>?>.filled(len, null);
if (parallel <= 0) {
void handleFuture(int index, Future<T> future) {
future.then((value) {
list[index] = FutureResult.success(value);
onSuccess?.call(index, value);
onComplete?.call(
index, FutureResultStatus.success, value, null, null);
}).catchError((e, s) {
list[index] = FutureResult.error(e, s);
onError?.call(index, e, s);
onComplete?.call(index, FutureResultStatus.error, null, e, s);
}).whenComplete(() {
if (--remaining == 0) {
completer.complete(List.unmodifiable(list.cast()));
}
});
}
for (int i = 0; i < len; i++) {
handleFuture(i, elementAt(i));
}
} else {
int running = 0;
int index = 0;
final queue = Queue<Future<T>>.from(this);
void exec() {
void handleFuture(int index, Future<T> future) {
future.then((value) {
list[index] = FutureResult.success(value);
onSuccess?.call(index, value);
onComplete?.call(
index,
FutureResultStatus.success,
value,
null,
null,
);
}).catchError((e, s) {
list[index] = FutureResult.error(e, s);
onError?.call(index, e, s);
onComplete?.call(index, FutureResultStatus.error, null, e, s);
}).whenComplete(() {
if (--remaining == 0) {
completer.complete(List.unmodifiable(list.cast()));
}
running--;
exec();
});
}
while (queue.isNotEmpty && running < parallel) {
running++;
final future = queue.removeFirst();
handleFuture(index++, future);
}
}
exec();
}
return completer.future;
}
}
enum FutureResultStatus {
success,
error,
;
}
class FutureResult<T> {
factory FutureResult.success(T value) {
return FutureResult._success(FutureResultStatus.success, value);
}
factory FutureResult.error(Object error, StackTrace stackTrace) {
return FutureResult._error(FutureResultStatus.error, error, stackTrace);
}
FutureResult._success(this.status, this._value);
FutureResult._error(this.status, this._error, this._stackTrace);
final FutureResultStatus status;
late final T _value;
late final Object _error;
late final StackTrace _stackTrace;
FutureOr<R?> when<R>({
FutureOr<R> Function(T value)? success,
FutureOr<R?> Function(Object error, StackTrace stackTrace)? error,
}) {
switch (status) {
case FutureResultStatus.success:
return success?.call(_value);
case FutureResultStatus.error:
return error?.call(_error, _stackTrace);
}
}
@override
String toString() {
return 'FutureResult(status: $status, ${when(success: (value) => 'value: $_value', error: (e, s) => 'error: $_error, stackTrace: $_stackTrace')})';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment