flushDefers function

FutureOr flushDefers({
  1. void onActionStart(
    1. dynamic key,
    2. String? category
    )?,
  2. void onActionDone(
    1. dynamic key,
    2. String? category
    )?,
  3. void onError(
    1. dynamic ex,
    2. StackTrace st
    )?,
  4. Duration? repeatLater,
})

Force all deferred task (queued by defer) to execute. If the task given in defer returns an instance of Future, this method will wait until it completes.

  • onActionStart - (optional) If specified, it is called when an action starts.
  • onActionDone - (optional) If specified, it is called when an action has been done.
  • onError - (optional) used to process the error thrown by a deferred task. If not specified, the exception won't be caught and will terminate this method.
  • repeatLater - If specified, it will continue to flush any new deferred function (registered via defer when flusing existing deferred functions). Before continue, it will wait the duration specified in repeatLater. Default: null (not to repeat).

Implementation

FutureOr flushDefers({void onActionStart(key, String? category)?,
    void onActionDone(key, String? category)?,
    void onError(ex, StackTrace st)?, Duration? repeatLater}) {
  if (_defers.isEmpty && _runnings.isEmpty) return null;

  final ops = <Future>[],
    defers = _defers;
  _defers = HashMap<_DeferKey, _DeferInfo>();

  for (final dfkey in defers.keys) {
    try {
      final di = defers[dfkey]!;
      di.timer.cancel();

      final key = dfkey.key,
        category = dfkey.category;
      onActionStart?.call(key, category);

      final exec = _executor;
      if (exec != null) {
        final op = exec(key, di.task, category, onError: onError,
            onActionDone: onActionDone == null ?
              null: () => onActionDone(key, category));
        if (op is Future) ops.add(op);

      } else {
        var op = di.task(key);
        if (op is Future) {
          Future ft = op;
          if (onActionDone != null)
            ft = ft.then((_) => onActionDone(key, category));
          if (onError != null)
            ft = ft.catchError(onError);
          ops.add(ft);
        } else {
          onActionDone?.call(key, category);
        }
      }
    } catch (ex, st) {
      if (onError != null) onError(ex, st);
      else rethrow;
    }
  }

  ops.addAll(_runnings);
  Future result = Future.wait(ops); //wait => run in parallel

  if (repeatLater != null) //spec: null => not repeat
    result = result.then(
        (_) => Future.delayed(repeatLater,
          () => flushDefers(onActionStart: onActionStart,
            onActionDone: onActionDone, onError: onError,
            repeatLater: repeatLater)));
  return result;
}