【问题标题】:Futures/Promises, and tracking down bugs期货/承诺,并追踪错误
【发布时间】:2026-01-07 13:35:02
【问题描述】:

简而言之,Futures (dart) 或 Promises (js) 似乎为可怕的回调提供了一种模糊有用的解决方案。

对于大型软件,例如,当您与之交谈的服务器开始返回垃圾,触发深埋在第三方代码中的迄今未发现的异常时,就会出现问题。此时,在一个令人难以置信的长链中的某个地方,以 catchError 终止,您将成为新的“空指针异常”之类的幸运接收者。它从哪里来的?谁知道?显然,我们不会使用这些技术神奇地获得调用堆栈,并且没有任何有用的跟踪信息 - 在这个巨大的链中,某些特定的函数可能会被调用 50 次,并且在某些任意调用时,会引发错误。

遇到这种情况时最好采用什么策略?

【问题讨论】:

  • 好吧,首先,不要有一个长系列,然后是catchError。构建您的代码,以便您执行错误检查,以捕获接近源的错误。
  • 问题是,一旦你开始编写使用 Promise 的库,你通常会以一长串的 then 结尾——库的每一层都构建一个更长的链,(除非我弄错了)。通过在库调用的外围使用 catchError 我想你可以手动包装错误并在最后创建一个巨大的“跟踪”,希望有一些信息,但不能保证某个地方的某个库不会做经典的等价物重新抛出错误并丢失堆栈信息(在这种情况下,每个人都必须玩相同的构建跟踪游戏)。我在这里错过了什么吗?
  • 不,你没有遗漏任何东西,而且你不能对其他库的结构做太多事情。但是您可以将自己的代码构造为具有 .then().catchError() 配对,而不是让一系列的 then() 调用被 catchError() 调用闲置。
  • 嗯。我想下一个问题是——如果我的库发生了 catchError,如果我试图构建一个跟踪,我可以非常可行地破坏 your 外部库,通过以一种你不知道的方式包装一个错误预计。似乎现阶段的期货/承诺并不能特别好地处理错误,如下所述:groups.google.com/a/dartlang.org/d/topic/misc/x-LynnxPYDU/…。似乎可以改进一般原则,但我们还没有做到。这使得在 nodejs 或 dart 上押注农场目前在生产中的前景相当可怕。
  • 我认为您想要的 Zones 正在脱离实验阶段。 api.dartlang.org/docs/releases/latest/…

标签: dart promise future dart-async


【解决方案1】:

即将推出的名为“区域”的功能在这里应该会有所帮助。另外,请查看getAttachedStackTrace

此示例打印“catchError 内部”:

import 'dart:async';

void main() {
  runZonedExperimental(() {
    new Future.value(1)
      .then((v) => v)
      .then((v) => throw new ArgumentError('testing'))
      .then((v) => v)
      .catchError((e) => print('inside of catchError'));
  },
  onError: print);
}

这个例子打印'in onError':

import 'dart:async';

void main() {
  runZonedExperimental(() {
    new Future.value(1)
      .then((v) => v)
      .then((v) => throw new ArgumentError('testing'))
      .then((v) => v);
  },
  onError: (e) => print('in onError'));
}

此示例打印“in onError: Illegal argument(s): testing”:

import 'dart:async';

void main() {
  runZonedExperimental(() {
    new Future.value(1)
      .then((v) => v)
      .then((v) => throw new ArgumentError('testing'))
      .then((v) => v);
  },
  onError: (e) => print('in onError: $e'));
}

此示例打印出堆栈跟踪,其中包含原始异常发生的文件和行号:

#0      main.<anonymous closure>.<anonymous closure> (file:///Users/sethladd/dart/zoneexperiment/bin/zoneexperiment.dart:7:20)

代码:

import 'dart:async';

void main() {
  runZonedExperimental(() {
    new Future.value(1)
      .then((v) => v)
      .then((v) => throw new ArgumentError('testing'))
      .then((v) => v);
  },
  onError: (e) => print(getAttachedStackTrace(e)));
}

区域应该在 1.0 之前退出实验。

getAttachedStackTrace 的文档:http://api.dartlang.org/docs/releases/latest/dart_async.html#getAttachedStackTrace

runZoned 的文档:http://api.dartlang.org/docs/releases/latest/dart_async.html#runZonedExperimental

【讨论】: