execute method

  1. @nonVirtual
R? execute(
  1. T parameter
)

Execute the asynchronous operation.

This method behaves differently for past execute call and its result. If the past operation with same parameter was completed successfully, this method returns its result. If the past operation with same parameter was failed with error, this method throws it as AsyncError. If the past operation with same parameter is still in-progress, this method do nothing and returns "initial value". Else, this method initiate async operation (call executeAsync), and returns "initial value".

Note that you can change the state with reset or cancel method. In addition, this method debounces continous execution. Specifically, it logically holds deque of requests and pops only the last one.

Note that the result of executeAsync is always spawn asynchronously. That means even if the executeAsync itself throws exception before any await expression, status property will be changed to AsyncOperationStatus.failed in next event loop. So, the result never be observed before any awaiting.

Implementation

@nonVirtual
R? execute(T parameter) {
  switch (_state.status) {
    case AsyncOperationStatus.completed:
      if (_isAlreadyHandled(parameter)) {
        _log.fine(
          () => 'Async operation result for parameter $parameter is cached.',
        );
        return _state.result;
      }
      break;
    case AsyncOperationStatus.failed:
      if (_isAlreadyHandled(parameter)) {
        _log.fine(
          () => 'Async operation error for parameter $parameter is cached.',
        );
        throw _state.error!;
      }
      break;
    case AsyncOperationStatus.initial:
      break;
    case AsyncOperationStatus.inProgress:
      if (_isAlreadyHandled(parameter)) {
        _log.fine(
          () =>
              'Async operation result for parameter $parameter is in progress, returns cached value.',
        );
        // Do nothing
        return _state.result;
      }

      break;
  }

  final shouldInvoke = _processingValue == null;
  _nextValue = _NullableValueHolder(parameter);
  if (shouldInvoke) {
    _log.fine(() => 'Begin async operation.');
    _executeAsync();
  }

  final synchronousError = _state.error;
  if (synchronousError != null) {
    // If executeAsync() throws exception synchronously,
    // the thrown error is catched and cached.
    // So throw it now.
    throw synchronousError;
  }

  _log.fine(() => 'Returns default result.');
  // Returns "initial value".
  return _state.result;
}