I have a function that makes an API call and usually the response is received after a delay of anywhere between 50 milliseconds to 6 seconds. I want the result to arrive exactly at 1500 milliseconds if the API call completed within 1500 milliseconds, and if the API response completed after 1500 milliseconds, it should return the result as soon as the response is received.
I tried using this:
final result = await Future.delayed(Duration(milliseconds: 1500,() async => await apiCall();
But the problem with this is that the apiCall()
function is getting called only after the delay of 1500 mils.
Is there a direct way in dart to achieve this? Have anyone tried this before?
It's fairly straightforward to make a helper function that measures the amount of time taken by the API call and then adds an appropriate delay before returning the result:
Future<R> callWithMinimumDuration<R>(
Future<R> Function() func,
Duration minimumDuration,
) async {
var stopwatch = Stopwatch()..start();
var result = await func();
var delta = minimumDuration - stopwatch.elapsed;
if (delta > Duration.zero) {
await Future.delayed(delta);
}
return result;
}
And then you'd invoke it with:
var result = await callWithMinimumDuration(apiCall, Duration(milliseconds: 1500));
Alternatively, you could use Future.wait
to combine the original Future
with a Future.delayed
. However, Future.wait
wants Future
s with homegeneous types, so you'd either need casts (whether explicit or implicit, if implicit dynamic
casts are allowed):
Future<R> callWithMinimumDuration<R>(
Future<R> Function() func,
Duration minimumDuration,
) async =>
(await Future.wait<Object?>([func(), Future.delayed(minimumDuration)]))[0]
as R;
or use an assignment technique to deal with heterogeneous Future
s:
Future<R> callWithMinimumDuration<R>(
Future<R> Function() func,
Duration minimumDuration,
) async {
late R result;
await Future.wait([
() async {
result = await func();
}(),
Future.delayed(minimumDuration),
]);
return result;
}
You also could use one of the .wait
extensions, but proper error-handling would be a bit more work:
Future<R> callWithMinimumDuration<R>(
Future<R> Function() func,
Duration minimumDuration,
) async {
try {
return (await (func(), Future.delayed(minimumDuration)).wait).$1;
} on ParallelWaitError catch (e, st) {
Error.throwWithStackTrace(e.errors.$1, st);
}
}