dart Future引发错误,未在try-catch块中捕获wait()

kr98yfug  于 2022-12-16  发布在  其他
关注(0)|答案(1)|浏览(186)

我不明白为什么下面代码中addItem方法抛出的错误没有在try-catch块中捕获

void main() async {
  var executor = Executor();
  var stream = Stream.fromIterable([0, 1, 2, 3, 4, 5, 6, 7]);
  try {
    await for (var _ in stream) {
      executor.submit(() => demoMethod());
    }
    await executor.execute();
  } catch (e) {
    print(e);
  }
}

Future<void> demoMethod() async {
  var list = [1, 2, 3, 1, 4, 5];
  var executor = Executor();
  var test = Test();

  for (var element in list) {
    executor.submit(() => test.addItem(element));
  }

  await executor.execute();
  test.list.forEach(print);
}

class Test {
  var list = <int>[];

  Future<void> addItem(int i) async {
    if (list.contains(i)) {
      throw Exception('Item exists');
    }
    list.add(i);
  }
}

class Executor {
  final List<Future<void>> _futures = [];
  bool _disposed = false;

  void submit(Future<void> Function() computation) {
    if (!_disposed) {
      _futures.add(computation());
    } else {
      throw Exception('Executor is already disposed');
    }
  }

  Future<void> execute() async {
    await Future.wait(_futures, eagerError: true);
    _disposed = true;
  }
}

但以下代码能够正确捕获错误

void main() async {
  var executor = Executor();
  try {
    for (var i = 0; i < 10; i++) {
      executor.submit(() => demoMethod());
    }
    await executor.execute();
  } catch (e) {
    print(e);
  }
}

我猜这与流处理有关。

yeotifhr

yeotifhr1#

是小溪。
在其他例子中,我们同步运行循环a,调用Executor.submit进行所有计算,然后立即调用executor.execute(),在调用返回future的函数和Future.wait开始等待future之间没有异步间隙。
在流代码中,每个流事件通过调用Executor.submit启动一个异步计算,这将创建一个future,将其存储在一个列表中,然后返回等待流。
如果future在流结束和Future.wait被调用之前完成,并出现错误,那么future还没有附加错误处理程序,错误被认为是未处理的,并报告给当前Zone的未捕获错误处理程序。这里是根区域,这意味着它是一个全局未捕获错误,可能会导致整个程序崩溃。
你需要确保将来不会认为它的错误是未处理的,最简单的方法是将submit修改为:

void submit(Future<void> Function() computation) {
    if (!_disposed) {
      _futures.add(computation()..ignore());
    } else {
      throw StateError('Executor is already disposed');
    }
  }

..ignore()告诉未来,没有错误处理程序是可以的。你知道,因为代码稍后会返回并调用executor.execute,所以任何错误仍然会被报告,所以稍微推迟一点应该是安全的。这就是Future.ignore的用途。
(Also我将Exception更改为StateError,因为您应该使用StateError来报告使用已被处置或停用的对象的人员。)

相关问题