compute<Q, R> function

Future<R> compute <Q, R>(ComputeCallback<Q, R> callback, Q message, { String debugLabel })

Spawn an isolate, run callback on that isolate, passing it message, and (eventually) return the value returned by callback.

This is useful for operations that take longer than a few milliseconds, and which would therefore risk skipping frames. For tasks that will only take a few milliseconds, consider scheduleTask instead.

Q is the type of the message that kicks off the computation.

R is the type of the value returned. The callback argument must be a top-level function, not a closure or an instance or static method of a class.

There are limitations on the values that can be sent and received to and from isolates. These limitations constrain the values of Q and R that are possible. See the discussion at SendPort.send. The debugLabel argument can be specified to provide a name to add to the Timeline. This is useful when profiling an application.


Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message, { String debugLabel }) async {
  profile(() { debugLabel ??= callback.toString(); });
  final Flow flow = Flow.begin();
  Timeline.startSync('$debugLabel: start', flow: flow);
  final ReceivePort resultPort = ReceivePort();
  final ReceivePort errorPort = ReceivePort();
  final Isolate isolate = await Isolate.spawn<_IsolateConfiguration<Q, R>>(
    _IsolateConfiguration<Q, R>(
    errorsAreFatal: true,
    onExit: resultPort.sendPort,
    onError: errorPort.sendPort,
  final Completer<R> result = Completer<R>();
  errorPort.listen((dynamic errorData) {
    assert(errorData is List<dynamic>);
    assert(errorData.length == 2);
    final Exception exception = Exception(errorData[0]);
    final StackTrace stack = StackTrace.fromString(errorData[1]);
    if (result.isCompleted) {
      Zone.current.handleUncaughtError(exception, stack);
    } else {
      result.completeError(exception, stack);
  resultPort.listen((dynamic resultData) {
    assert(resultData == null || resultData is R);
    if (!result.isCompleted)
  await result.future;
  Timeline.startSync('$debugLabel: end', flow: Flow.end(;
  return result.future;