【问题标题】:Unhandled Exception in DartDart 中未处理的异常
【发布时间】:2012-12-11 18:50:56
【问题描述】:

我在 Dart 中编写了一个网络服务器,并且有一个关于异常的问题。在我的 HttpServer 请求处理程序中,我在整个方法周围添加了一个 try-catch 块:

try{
 ...
} catch(e) {
 ...
}

所以我希望这可以防止任何客户端请求使网络服务器崩溃。问题在于,当从该块中抛出某些异常(大量嵌套在其他模块中,但仍从该块启动)时,它可能崩溃。以下是此类异常的示例:

Unhandled exception:
FutureUnhandledException: exception while executing Future
  Illegal argument(s)
original stack trace:
  #0      _StringBase._createFromCodePoints (dart:core-patch:1403:3)
  #1      _StringBase.createFromCharCodes (dart:core-patch:1400:33)
  #2      String.String.fromCharCodes (dart:core-patch:1788:43)
  #3      _StringDecoderBase.decoded (dart:io:6485:12)
  #4      _File.readAsString.<anonymous closure> (dart:io:1307:29)
  #5      _FutureImpl.transform.<anonymous closure> (bootstrap:881:37)

 #0      _FutureImpl._complete (bootstrap:844:11)
 #1      _FutureImpl._complete (bootstrap:848:5)
 #2      _FutureImpl._setException (bootstrap:873:14)
 #3      _CompleterImpl.completeException (bootstrap:948:30)
 #4      _FutureImpl.transform.<anonymous closure> (bootstrap:884:36)
 #5      _FutureImpl._complete (bootstrap:840:19)
 #6      _FutureImpl._complete (bootstrap:848:5)
 #7      _FutureImpl._setValue (bootstrap:862:14)
 #8      _CompleterImpl.complete (bootstrap:945:26)
 #9      _File.readAsBytes.<anonymous closure> (dart:io:1281:25)
 #10     _BaseDataInputStream._checkScheduleCallbacks.issueCloseCallback (dart:io:6345:59)
 #11     _Timer._createTimerHandler._handleTimeout (dart:io:6918:28)
 #12     _Timer._createTimerHandler._handleTimeout (dart:io:6926:7)
 #13     _Timer._createTimerHandler.<anonymous closure> (dart:io:6934:23)
 #14     _ReceivePortImpl._handleMessage (dart:isolate-patch:37:92)

为什么这不会在 try-catch 块中被捕获?它在从其中调用的代码中抛出(即使它没有显示在堆栈跟踪中)。

我希望我错过了一些关于异常如何在 Dart 中工作的内容,所以我希望你能启发我 :)

【问题讨论】:

  • 可以添加try块的内容吗?
  • 抱歉,如果我必须包含与异常相关的所有调用代码,那将是数千行... 这是一个非常复杂的 Web 服务器,此异常在处理基于 Web 的 IDE 后端的模块。我希望有人能告诉我类似的事情,我需要做更多的事情来捕捉“期货”中的异常,或者它必须发生在创建未来的地方......如果我尝试读取 .png 文件,则会生成异常作为文本。

标签: dart


【解决方案1】:

使用Future,你必须使用catchError方法来处理异常。

【讨论】:

  • 你能举个例子吗?
  • 答案已过时。我刚刚更新了可以找到示例的链接。
  • 好的,但是如果链接又过期了怎么办?我建议在您的答案中发布其中一个示例或创建您自己的示例
  • 这篇文章给出了如何使用catchError的一个很好的例子:woolha.com/tutorials/…
【解决方案2】:

一旦你意识到发生了什么,理解问题就很简单了。

问题在于:传统控制流构造(ifwhiletry/catch/finallyreturn)的语义纯粹是同步。他们期望程序的流程就像它的源代码流程一样。看看这个:

1      try {
2        while (...) {
3          if (...) {
4            doSomething();
5            doSomethingElse();
6          }
7        }
8      } catch (e) {
9        print('oh no, something wrong happen! error: $e');
10     } finally {
11       print('done!');
12     }

这个程序作为一个序列工作。第1行在第2行之前执行,在第3行之前执行等等。第5行在第4行之后立即执行。第11行在第7行之后执行,如果发生异常,第11行也会在第9行之后执行。就是这样同步的意思。

但是,同步程序不再足够好。事件处理自然是异步,您会发现无处不在的事件——从用户界面到高度可扩展的网络服务器。所以如果你写

1      try {
2        var text = 'this will be replaced by the content of the file';
3        new File('...').readAsText().then((result) {
4          text = result;
5          doSomethingThatMightCauseAnException(text);
6          print('read file, got $text');
7        });
8        print('invoked file read');
9        return text;
10     } catch (e) {
11       print('error: $e');
12     }

您必须了解您正在调用异步操作(readAsText 方法)。在这个程序中,第 2 行在第 1 行之后执行,第 3 行在第 2 行之后执行,但第 4 行在第 3 行之后执行。文件读取是异步调用的(想想“在后台”)程序继续。所以在这种情况下,在第 3 行之后,您将直接进入第 8 行。因此第 9 行(在第 8 行之后)上的 return 语句总是返回 'this will be replaced by the content of the file' 文本。

然后,程序继续运行,直到完成(退出main 函数)。但它不会停止,因为有一些代码在“后台”运行并且有一个为其注册的处理程序(您通过调用then 方法注册了处理程序)。一旦系统完成读取文件,它将调用处理程序(您传递给then 方法的匿名函数)。只有在没有注册某些异步调用的处理程序时,程序才能停止。

现在,您可能明白第 10 行的异常处理程序只能捕获第 3 行发生的错误(打开文件时出错)。但如果第 5 行发生异常,则无法在第 10 行捕获,因为 catch 处理程序早已不复存在。

剩下的只是正确使用 API 的问题。如果你使用回调,你必须传递一个成功处理程序一个错误处理程序,如果你使用Futures,你必须使用成功处理程序调用then方法带有错误处理程序的handleException 方法。

【讨论】:

  • 我的这个答案刚刚出现在我的成就列表中,所以我想指出这是在之前 Dart得到async/await之前写的.从根本上来说它仍然是正确的,但使用async/await,体验会大不相同。
猜你喜欢
  • 2021-01-03
  • 2021-12-27
  • 2011-11-19
  • 2020-02-04
  • 1970-01-01
  • 2022-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多