callAsync<T> static method
@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();
}
}