2015-01-06 7 views
5

Si consideri il seguente codiceDart Errori nella multi-livello di codice asincrono

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(); 
} 

Quando viene eseguito, l'eccezione generata in doSomethingElse() è coinvolto in main(), e tutto funziona come previsto. Ma, diciamo che la persona che ha scritto il metodo doSomething() non ha capito che doSomethingElse() era asincrono, e invece ha scritto il seguente (si noti il ​​await mancante).

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

Ora l'eccezione non viene catturata affatto. Piuttosto, l'uscita appare come segue:

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> 

Quello che sta succedendo è che doSomething() sta tornando immediatamente, e poi qualche tempo dopo, in un altro contesto, doSomethingElse() sta gettando il suo errore, fermando immediatamente ogni esecuzione. So che una risposta a questo potrebbe essere "Bene, non farlo poi". ma sto considerando casi in cui potrei non avere il controllo sui metodi che sto chiamando (diciamo se fanno parte di una biblioteca).

Questa situazione porta ad un paio di domande relative:

  • Come l'autore di main(), c'è un modo posso essere certo che la mia chiamata a doSomething() non finirà con un'eccezione non gestita? O sono dipendente dall'autore di doSomething() per assicurarmi che tutte le possibili eccezioni siano gestite o propagate al futuro restituito? C'è un modo per collegare una sorta di gestore di errori globale che può catturare errori da Futures abbandonati?
  • Come autore di doSomething(), se non si desidera attendere doSomethingElse() (ad esempio, scrive in un registro ad esempio, quindi non ho bisogno dell'output né devo preoccuparmi di errori di gestione). C'è qualcosa che posso fare per evitare errori in doSomethingElse() dall'arresto del programma oltre a racchiudere ogni chiamata di esso in un blocco try/catch (che può essere ingombrante e facilmente trascurato)?
  • Come autore di doSomethingElse(), c'è qualche schema che posso usare che mi permette di lanciare Eccezioni in modo che i chiamanti che attendono il completamento del Futuro possano gestire quell'eccezione mentre i chiamanti che non aspettano il futuro don dovresti preoccuparti di prendere l'eccezione? Il mio miglior pensiero al riguardo è di restituire un oggetto speciale piuttosto che lanciare un'eccezione, ma questo aggiunge un sacco di cruft extra e rende il metodo molto più difficile da usare.

Nota: sto usando asincrone/await sintassi qui, ma la questione dovrebbe essere altrettanto rilevante per una costruzione basata più strettamente Future (dove si torna un nuovo futuro nel doSomething() invece di .then() ing fuori quello da doSomethingElse()

+2

è possibile gestire questi errori con [Zone] (https: // www. dartlang.org/articles/zones/), e ci sono piani per aggiungere un gestore di errori isolato di primo livello, ma non penso che questo sia ancora implementato. –

+0

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

+0

Le funzioni oi metodi di classe nelle librerie correttamente implementate sarebbero esplicitamente sincroni o asincroni, con solo le funzioni che realmente necessitano essere asincroni essere così - proprio come le funzioni di libreria sono ora, restituendo un futuro se sono asincroni. Non ho ancora usato questa sintassi, ma presumo che gli editori segnaleranno un errore quando rilevano disallineamenti attesa/asincrona. –

risposta

6

non rilevate errori asincroni vengono gestiti al gestore degli errori della zona corrente. Quello che state vedendo è gestore di errori di root-zone riportando l'errore come non rilevato, che termina anche l'isolato.

quello che vuoi è di introdurre un gestore di errore diverso per il codice, eseguendolo attraverso runZoned con un gestore di errori:

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