call method

Future<R> call(
  1. List args
)

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;
}