Last active
October 8, 2022 08:19
-
-
Save iota9star/06e53530f75de974b4aeb7dc0c0ab3ea to your computer and use it in GitHub Desktop.
This file contains 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'; | |
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