首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用Completer时最有价值的StackTrace丢失

使用Completer时最有价值的StackTrace丢失
EN

Stack Overflow用户
提问于 2021-06-23 14:38:11
回答 1查看 95关注 0票数 1

见下面的例子:

代码语言:javascript
运行
复制
import 'dart:async';

Future<void> main(List<String> arguments) async {
  try {
    await someMethod();
  } catch (e, st) {
    print("error: ${e}");
    print("st   : ${st}");
  }
}

Future<void> someMethod() async {
  final completer = Completer.sync();
  _scheduleCompletion(completer);
  await completer.future;
}

Future<void> _scheduleCompletion(Completer completer) async {
  Future.delayed(Duration(milliseconds: 1), () {
    try {
      [][0]; // simulating error
      completer.complete();
    } catch (e, st) {
      completer.completeError("error occured", st);
    }
  });
}

我收到以下产出:

代码语言:javascript
运行
复制
#0      List.[] (dart:core-patch/growable_array.dart:254:60)
#1      _scheduleCompletion.<anonymous closure> (file:///home/work/stuff/projects/dart-async-exceptions/bin/dart_async_exceptions.dart:26:9)
#2      new Future.delayed.<anonymous closure> (dart:async/future.dart:315:39)
#3      Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
#4      _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
#5      _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
#6      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

如您所见,堆栈跟踪不允许您查看导致错误的步骤。我所期望的是:

代码语言:javascript
运行
复制
[anonymous closure, where error actually happens]
[someMethod]
[main]

而我只看到最后一部分。

我知道有一个叫做跟踪的包,它允许你“用Chain.capture包装你的整个程序,你会很高兴的”。不幸的是,我的实际情况并不是那么简单,我不能简单地用"Chain.capture“来”包装我的程序“。不使用"Chain.capture“的另一个原因是,在某些情况下,它的onError处理程序会变得更糟,而不是简单的try/catch块。

此外,我想了解为什么会发生这种情况,以及我应该做些什么来修复我的程序,这样就不会丢失部分有价值的跟踪。

更新(基于Irn的回答):

让我们重新编写someMethod,而不是使用completer,而是调用另一个异步方法:

代码语言:javascript
运行
复制
Future<void> someMethod() async {
  await someOtherMethod();
}

Future<void> someOtherMethod() async {
  throw "another error";
}

在这种情况下,我将有以下跟踪:

代码语言:javascript
运行
复制
#0      someOtherMethod (file:///home/work/stuff/projects/dart-async-exceptions/bin/dart_async_exceptions_original.dart:24:3)
<asynchronous suspension>
#1      someMethod (file:///home/work/stuff/projects/dart-async-exceptions/bin/dart_async_exceptions_original.dart:19:3)
<asynchronous suspension>
#2      main (file:///home/work/stuff/projects/dart-async-exceptions/bin/dart_async_exceptions_original.dart:5:5)
<asynchronous suspension>

正如您所看到的,它包含所有调用--主-> someMethod -> someOtherMethod,这使您可以缩小问题范围。正如我所理解的,在这种情况下,当我们在事件循环上调度调用时,我们也应该失去所有的东西。但我们认为一切都如预期的那样运作。为什么会这样呢?

About stack_trace package:我很想使用它,但我做了一些小实验,看起来有时它提供的跟踪比try/catch提供的更糟。但这是另一个问题的主题;)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-24 08:31:27

简单的回答是,您无法跟踪不存在的堆栈。

Dart的异步代码是基于事件循环的。当您执行await someFuture时,您的函数实际上使用Future.then设置了对该未来的回调,然后它返回。这会将堆栈展开,导致设置回调,并最终使堆栈返回到事件循环。(只有在计算await时,someFuture表达式才会立即被调用,如果在执行异步操作之前设法抛出,则会在await返回之前得到包含堆栈的堆栈跟踪)。

稍后,事件循环触发并调用回调,然后异步计算将继续进行。

原来的堆栈在那时不再存在,这就是为什么您看到堆栈跟踪返回到事件循环事件(这里是一个定时器,VM通过在特定时间发送端口事件来实现)。您看到的堆栈是唯一存在于您所要求的点上的堆栈。

可以使用package:stack_trace在调度回调的点捕获堆栈跟踪,然后堆栈跟踪包将记住该堆栈跟踪,直到回调运行为止,并尝试将其与回调期间报告(或捕获)的堆栈跟踪结合起来。由于您进行了大量回调,但通常不需要看到那么多堆栈跟踪,因此在每次回调时捕获堆栈都会对性能产生重大影响。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68101983

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档