callAsync<T> static method

Future<T> callAsync<T>(
  1. Function fn,
  2. List<Object?> args, {
  3. Object? getError,
  4. Object? clearError,
  5. String methodName = '',
})

@nitroAsync on web: there are no isolates, so fn runs on the main thread after a single event-loop hop. Long-running native work will jank the UI — prefer @nitroNativeAsync for genuinely asynchronous impls.

Implementation

static Future<T> callAsync<T>(
  Function fn,
  List<Object?> args, {
  Object? getError,
  Object? clearError,
  String methodName = '',
}) async {
  final cfg = NitroConfig.instance;
  final effective = cfg.effectiveLogLevel;
  final traceTimeline = cfg.timelineTracingEnabled;

  Future<T> dispatch() => Future<T>(() => Function.apply(fn, args) as T);

  if (effective != NitroLogLevel.verbose && !traceTimeline && cfg.slowCallThresholdUs == 0) {
    if (effective == NitroLogLevel.none) return await dispatch();
    try {
      return await dispatch();
    } catch (e, st) {
      _log(NitroLogLevel.error, methodName.isEmpty ? 'callAsync' : 'callAsync($methodName)', 'threw: $e', e, st);
      rethrow;
    }
  }

  final sw = effective != NitroLogLevel.none && (effective == NitroLogLevel.verbose || cfg.slowCallThresholdUs > 0) ? (Stopwatch()..start()) : null;
  final tag = methodName.isEmpty ? 'callAsync' : 'callAsync($methodName)';

  if (traceTimeline) developer.Timeline.startSync(_timelineLabel(tag));
  try {
    _log(NitroLogLevel.verbose, tag, 'dispatching inline (web has no isolates)');
    final result = await dispatch();
    _logCallTiming(sw, tag);
    return result;
  } finally {
    if (traceTimeline) developer.Timeline.finishSync();
  }
}