首页 > 解决方案 > Dart:如何“等待”Future.wait 的清理?

问题描述

以下面的代码为例,可以推断出 Future.wait 的 cleanUp 在调用时没有“等待” 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.wait 返回之前等待 cleanUp 运行。

有没有推荐的方法来解决这个问题,也许使用另一种方法?

标签: dartasync-await

解决方案


传递给的方法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);

...

推荐阅读