execute method

Future<void> execute(
  1. dynamic exec(), {
  2. dynamic onCancel()?,
  3. V? valueOnCancel,
})

Execute a closure either async or sync. The Executor is only called if all deferred cancels return false and only after all executionDeferrals have completed. If exec returns a future, its result is piped through to the onDone future, otherwise, the onDone future is completed with the result.

Implementation

Future<void> execute(dynamic Function() exec,
    {dynamic Function()? onCancel, V? valueOnCancel}) {
  // This function is very time-sensitive.
  // We are using explicit `Future`s to avoid breaking changes when the
  // behavior of `async` changes.
  // TODO(google): switch back to `async` with an explicit `await null;` at
  // the beginning of the function, once the migration is done.
  return Future.microtask(() {
    if (_locked) {
      throw StateError('Cannot execute, execution already in process.');
    }
    _locked = true;

    // Check for cancellations
    return _shouldCancel().then((shouldCancel) {
      _cancelled = shouldCancel;
      var shouldProceed = !_cancelled;
      _deferCompleter.complete(shouldProceed);
      if (shouldProceed) {
        // Wait for any execution deferrals.
        return _maybeWait().then((_) {
          _executeAndAttach(exec);
        });
      } else {
        _done = true;

        // FutureCancellations have cancelled this action. Run the onCancel,
        // then complete with [valueOnCancel].
        if (onCancel == null) {
          _executeCompleter.complete(valueOnCancel);
        } else {
          var cancelRes = onCancel();
          if (cancelRes is! Future) {
            _executeCompleter.complete(valueOnCancel);
          } else {
            // The action should resolve [onDone] with [valueOnCancel] if
            // canceled, so, while we need to await the cancel result, we want
            // to throw it away.
            _attachFuture(cancelRes.then(((_) => valueOnCancel!)));
          }
        }
        return null;
      }
    });
  });
}