Dart: как «ожидать» очистки Future.wait?

#dart #async-await

#dart #асинхронный-ожидание

Вопрос:

Взяв следующий код в качестве примера, можно сделать вывод, что очистка Future.wait не «ожидается» при вызове await Future.wait .

Если я не включу оператор «1 — должен ждать здесь», тест не пройдет.

 import 'package:test/test.dart';

void main() {
  test('test Future.wait', () async {
    final waitSeconds = 5;
    DateTime slowOkExecutedTime;
    DateTime slowErrorExecutedTime;
    DateTime cleanUpExecutedTime;
    DateTime slowCleanUpExecutedTime;

    Future slowOk() {
      return Future.delayed(Duration(seconds: waitSeconds), () {
        slowOkExecutedTime = DateTime.now();
        return true;
      });
    }

    Future slowError() {
      return Future.delayed(Duration(seconds: waitSeconds), () {
        slowErrorExecutedTime = DateTime.now();
        throw Exception("SlowError");
      });
    }

    Future slowCleanUp() {
      return Future.delayed(Duration(seconds: waitSeconds), () {
        slowCleanUpExecutedTime = DateTime.now();
        return true;
      });
    }

    try {
      await Future.wait([
        Future.microtask(() => slowOk()),
        Future.microtask(() => slowError()),
      ], cleanUp: (value) async {
        cleanUpExecutedTime = DateTime.now();

        expect(value, true);
        expect(slowOkExecutedTime != null, true);
        expect(
          cleanUpExecutedTime.isAfter(slowOkExecutedTime),
          true,
        );

        return await slowCleanUp();
      });
      fail("Should have thrown SlowError");
    } catch (error) {
      expect(error.toString().contains("SlowError"), true);
    }

    expect(slowOkExecutedTime != null, true);
    expect(slowErrorExecutedTime != null, true);
    expect(cleanUpExecutedTime != null, true);
    expect(slowCleanUpExecutedTime != null, false);

    // 1 - must wait here
    await Future.delayed(
        Duration(milliseconds: waitSeconds * 1000   10), () {});

    expect(slowCleanUpExecutedTime != null, true);
    expect(
      cleanUpExecutedTime.isAfter(slowOkExecutedTime),
      true,
    );
    expect(
      cleanUpExecutedTime.isAfter(slowErrorExecutedTime),
      true,
    );
    expect(
      slowCleanUpExecutedTime.isAfter(cleanUpExecutedTime),
      true,
    );
    final now = DateTime.now();

    print(
        'Clean up executed time: ${slowCleanUpExecutedTime.toIso8601String()}');
    print('                   Now: ${now.toIso8601String()}');

    expect(
      now.isAfter(slowCleanUpExecutedTime),
      true,
    );
  });
}

  

Я просто хочу дождаться запуска очистки перед Future.возвращается ожидание.

Есть ли рекомендуемый способ решения этой проблемы, возможно, с использованием другого подхода?

Ответ №1:

Переданный метод onCatch будет вызываться синхронно и не ожидает возвращаемого значения. Если вам нужно ожидать или возвращать что-либо в этом методе, вы можете пересмотреть, может ли быть другой способ сделать то, что вы делаете.

Если вам абсолютно необходимо, чтобы внешний контекст ожидал асинхронного onCatch метода, вам нужно будет поднять фьючерсы до внешнего контекста, чтобы вы могли ожидать их отдельно.

 final cleanUpFutures = <Future>[];
try {
  await Future.wait([
    Future.microtask(() => slowOk()),
    Future.microtask(() => slowError()),
  ], cleanUp: (value) {
    cleanUpFutures.push(() async {
      cleanUpExecutedTime = DateTime.now();

      expect(value, true);
      expect(slowOkExecutedTime != null, true);
      expect(
        cleanUpExecutedTime.isAfter(slowOkExecutedTime),
        true,
      );

      await slowCleanUp());
    }());
  });
  fail("Should have thrown SlowError");
} catch (error) {
  expect(error.toString().contains("SlowError"), true);
}

await Future.wait(cleanUpFutures);

...