2015-01-06 7 views
5

Rozważmy następujący kodDart Błędy w wielopoziomowym kodu asynchronicznego

import 'dart:async'; 

Future main() async { 
    try { 
    print("trying"); 
    await doSomething(); 
    print("success"); 
    } catch (e) { 
    print("caught"); 
    } 
} 

Future<int> doSomething() async { 
    await doSomethingElse(); 
    return 5; 
} 

Future<int> doSomethingElse() async { 
    throw new Exception(); 
} 

Po uruchomieniu wyjątek rzucony w doSomethingElse() się wciągnąć w main(), i wszystko działa zgodnie z oczekiwaniami. Ale, powiedzmy, osoba, która napisała metodę doSomething(), nie zdawała sobie sprawy, że doSomethingElse() była asynchroniczna, i zamiast tego napisała następującą (zanotuj brakującą await).

Future<int> doSomething() async { 
    doSomethingElse(); 
    return 5; 
} 

Teraz wyjątek nie zostanie w ogóle złapany. Raczej wyjście teraz wygląda tak:

trying 
success 
Unhandled exception: 
Uncaught Error: Exception 
Stack Trace: 
#0  doSomethingElse.<doSomethingElse_async_body> (file:///C:/code/test.dart:19:7) 
#1  Future.Future.<anonymous closure> (dart:async/future.dart:118) 
<snip> 

Co się dzieje jest to, że doSomething() wraca natychmiast, a potem jakiś czas później, w innym kontekście, doSomethingElse() rzuca swój błąd, natychmiast zatrzymać wszystkie wykonanie. Wiem, że odpowiedź na to może brzmieć: "Cóż, nie rób tego wtedy." ale rozważam przypadki, w których mogę nie mieć kontroli nad metodami, do których dzwonię (powiedz, czy są częścią biblioteki).

Sytuacja ta prowadzi do kilku pokrewnych pytania:

  • Jako autor main(), czy jest jakiś sposób mogę być pewny, że moje wezwanie do doSomething() nie zakończy się nieobsługiwany wyjątek? Czy jestem zależny od autora doSomething(), aby upewnić się, że wszystkie możliwe wyjątki są obsługiwane lub propagowane do zwróconej Przyszłości? Czy istnieje sposób na dołączenie jakiejś globalnej procedury obsługi błędów, która może wychwycić błędy z porzuconych kontraktów Futures?
  • Jako autor doSomething(), jeśli nie chcę czekać na doSomethingElse() (powiedzmy, że pisze na przykład w dzienniku, więc nie potrzebuję wyjścia ani nie muszę się martwić o błędy obsługi). Czy jest coś, co mogę zrobić, aby zapobiec błędom w doSomethingElse() od zatrzymania programu innego niż zawijanie każdego wywołania tego bloku try/catch (który może być uciążliwy i łatwo przeoczyć)?
  • Jako autor doSomethingElse(), istnieje jakiś wzór, którego mogę użyć, co pozwala mi rzutować wyjątki w taki sposób, że osoby oczekujące na zakończenie przyszłości mogą obsłużyć ten wyjątek, a osoby dzwoniące, które nie czekają na przyszłe wykłady. nie musisz się martwić o złapanie wyjątku? Moim zdaniem w tym względzie jest zwrócenie specjalnego obiektu zamiast wyrzucenia wyjątku, ale to dodaje wiele dodatkowych problemów i sprawia, że ​​metoda jest znacznie trudniejsza.

Uwaga: Używam asynchroniczny/Oczekujcie składnia tutaj, ale kwestia ta powinna być równie istotne dla ściślej przyszłej budowy bazie (gdzie można powrócić nową przyszłość w doSomething() zamiast .then() ing wyłączyć jedną z doSomethingElse()

+2

można obsługiwać te błędy z [stref] (https: // www. dartlang.org/articles/zones/) i są plany dodania procedury obsługi błędów najwyższego poziomu, ale nie sądzę, że jest to jeszcze zaimplementowane. –

+0

https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:isolate.Isolate#id_addErrorListener –

+0

Funkcje lub metody klasy we właściwie zaimplementowanych bibliotekach jawnie byłyby synchroniczne lub asynchroniczne, a tylko te funkcje, które naprawdę potrzebują być tak asynchronicznym - tak jak teraz funkcje biblioteczne, zwracając przyszłość, jeśli są asynchroniczne. Nie używałem jeszcze tej składni, ale zakładam, że edytujący zgłosi błąd, gdy wykryją niedopasowania oczekujące/asynchroniczne. –

Odpowiedz

6

Uncaught błędy asynchroniczne są obsługiwane do obsługi błędów w bieżącej strefie. Co widzisz jest obsługi błędów na głównych Zone zgłaszanie błędu jako nieprzechwyconego, co również kończy izolację.

Co chcesz jest wprowadzenie innego obsługi błędów dla kodu, poprzez uruchomienie go przez runZoned z obsługi błędów:

import "dart:async"; 
main() { 
    runZoned(() async { 
    try { 
     print("trying"); 
     await doSomething(); 
     print("success"); 
    } catch (e) { 
     print("caught"); 
    } 
    }, onError: (e, s) { 
    print("uncaught"); 
    }); 
}