Dart中未处理的异常

时间:2012-12-11 18:50:56

标签: dart

我在Dart写了一个网络服务器并且有关于例外的问题。在我的HttpServer requesthandler中,我在整个方法中添加了一个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中异常如何工作的内容,所以我希望你能开导我:)

2 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:3)

一旦你意识到发生了什么,理解这个问题非常简单。

问题是:传统控制流结构(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行在第3行之前执行第2行。在第4行之后立即执行第5行。在第7行之后执行第11行,如果发生异常,第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​​的问题。如果使用回调,则必须传递成功处理程序错误处理程序,如果使用Future,则必须成功调用then方法处理程序带有错误处理程序的handleException方法。