call method
Implementation
Future<R> call(List<dynamic> args) async {
final key = _makeKey(args);
final cached = _cache[key];
final now = DateTime.now().millisecondsSinceEpoch;
// Populate cache -- cold miss with in-flight dedup
if (cached == null) {
final pending = _inFlight[key];
if (pending != null) return pending;
final promise = _fn(args);
_inFlight[key] = promise;
try {
final result = await promise;
// Identity-guard: cache.clear() during the await should discard
if (_inFlight[key] == promise) {
_cache[key] = _CacheEntry(value: result, timestamp: now);
}
return result;
} finally {
if (_inFlight[key] == promise) {
_inFlight.remove(key);
}
}
}
// If stale and not already refreshing
if (now - cached.timestamp > cacheLifetime.inMilliseconds &&
!cached.refreshing) {
cached.refreshing = true;
final staleEntry = cached;
_fn(args)
.then((newValue) {
if (_cache[key] == staleEntry) {
_cache[key] = _CacheEntry(
value: newValue,
timestamp: DateTime.now().millisecondsSinceEpoch,
);
}
})
.catchError((_) {
if (_cache[key] == staleEntry) {
_cache.remove(key);
}
});
return cached.value;
}
return _cache[key]!.value;
}