waitF<R> function
Waits for a list of FutureOr values and transforms the results.
Implementation
FutureOr<R> waitF<R>(
Iterable<_TFactory<dynamic>> itemFactories,
_TSyncOrAsyncMapper<Iterable<dynamic>, R> callback, {
_TOnErrorCallback? onError,
bool eagerError = true,
_TOnCompleteCallback? onComplete,
}) {
// Single in-order buffer: holds either raw sync values or pending Futures.
// This guarantees the callback observes results in the same order the
// caller passed them in — `consec2(asyncA, syncB, ...)` must see `[A, B]`,
// not `[B, A]`. The previous implementation split sync/async into two
// buffers and concatenated them, silently reordering arguments.
final buffer = <dynamic>[];
var hasAsync = false;
_Error? syncError1;
for (final itemFactory in itemFactories) {
try {
final item = itemFactory();
buffer.add(item);
if (item is Future) hasAsync = true;
} catch (e, s) {
if (eagerError) {
return _handleErrorAndComplete(_Error(e, s), onError, onComplete);
}
// Record only the first sync error for reporting, but always push a
// placeholder Future.error into the buffer so its length stays aligned
// with the input. Otherwise `consecN`'s positional access drifts when
// multiple sync factories throw under `eagerError: false`.
syncError1 ??= _Error(e, s);
buffer.add(Future<dynamic>.error(e, s));
hasAsync = true;
}
}
if (!hasAsync) {
return _handleSyncPath(
syncError1,
buffer,
callback,
onError,
onComplete,
);
}
final asyncBuffer = buffer
.map<Future<dynamic>>((e) => e is Future ? e : Future<dynamic>.value(e))
.toList(growable: false);
return _handleAsyncPath(
syncError1,
asyncBuffer,
eagerError,
callback,
onError,
onComplete,
);
}