5

Dart で Web サーバーを作成しましたが、例外について質問があります。私の HttpServer requesthandler では、メソッド全体に try-catch ブロックを追加しました。

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

したがって、これにより、クライアント要求が Web サーバーをクラッシュさせるのを防ぐことができると期待していました。問題は、このブロック内から特定の例外がスローされるとクラッシュする可能性があることです (他のモジュールに大きくネストされていますが、このブロックから開始されます)。以下は、このような例外の例です。

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 で例外がどのように機能するかについて何か見逃していると思いますので、教えていただければ幸いです :)

4

2 に答える 2

7

Futureでは、 catchErrorメソッドを使用して例外を処理する必要があります。

于 2012-12-11T20:47:00.660 に答える
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行目の前に実行されます.5行目は4行目の直後に実行されます.11行目は7行目の後に実行されます.例外が発生した場合は9行目の後に11行目も実行されます.同期手段。

ただし、同期プログラムはもはや十分ではありません。イベント処理は本来非同期であり、ユーザー インターフェイスから非常にスケーラブルなネットワーク サーバーまで、あらゆる場所でイベントが発生します。だからあなたが書くなら

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 行目に直接到達します。そのため、return9 行目のステートメント (8 行目に続く) は、常に'this will be replaced by the content of the file'テキストを返します。

その後、プログラムは完了するまで続けます (main関数を終了します)。しかし、 「バックグラウンドで」実行されているコードがあり、そのコード用に登録されたハンドラーがあるため、停止しません(メソッドを呼び出してハンドラーを登録しましたthen)。システムがファイルの読み取りを完了すると、ハンドラー (thenメソッドに渡した無名関数) が呼び出されます。何らかの非同期呼び出しのハンドラーが登録されていない場合にのみ、プログラムを停止できます。

これで、10 行目の例外ハンドラーは、3 行目で発生したエラー (ファイルを開く際のエラー)のみをキャッチできることがおわかりいただけたと思います。しかし、5 行目で例外が発生した場合、10 行目ではキャッチできませんcatch

残りは、API を適切に使用するだけの問題です。コールバックを使用する場合は、成功ハンドラーエラー ハンドラーを渡す必要があります。s を使用する場合は、成功ハンドラー使用してメソッドFutureを呼び出し、エラー ハンドラーを使用してメソッドを呼び出す必要があります。thenhandleException

于 2012-12-12T08:17:29.727 に答える