withDelay method
If the time it takes for this to complete is less than
minOperationTime
, then a Future.delayed is awaited for
the remaining time. The delay also affects any errors of this Future.
The Future returned by this method will take at least
as much time as
specified by minOperationTime
to complete.
Implementation
Future<T> withDelay(
Duration minOperationTime, {
Duration threshold = const Duration(milliseconds: 50),
}) async {
if (minOperationTime.isNegative) {
throw ArgumentError.value(
minOperationTime,
"minOperationTime",
"Must be a positive duration",
);
}
if (threshold.isNegative) {
throw ArgumentError.value(
threshold,
"threshold",
"Must be a positive duration",
);
}
if (minOperationTime < threshold) {
throw ArgumentError.value(
minOperationTime,
"minOperationTime",
"The minimum operation time cannot be less than the threshold time",
);
}
Result<T> res;
final watch = clock.stopwatch();
watch.start();
try {
res = Result.value(await this);
// Forward error objects of any type.
// ignore: avoid_catches_without_on_clauses
} catch (err, st) {
res = Result.error(err, st);
} finally {
watch.stop();
}
final delta = minOperationTime - watch.elapsed;
// Only wait if we have at least threshold.
if (delta >= threshold) {
// TODO(obemu): Maybe find a better fix for the following hack.
// If the operation completed too fast then we wait for
// [minOperationTime], because waiting for [delta]
// in this case may not work (depends on the platform and
// compilation type) so that [withDelay] actually causes a delay of at
// least [minOperationTime].
final delay = watch.elapsed < const Duration(milliseconds: 100)
? minOperationTime
: delta;
await Future.delayed(delay);
}
if (res.asError case final ErrorResult err) {
throw Error.throwWithStackTrace(err.error, err.stackTrace);
}
return res.asValue!.value;
}