I have a HTML5 worker which sends values with postMessage. Sometimes (for example if the result is a function) the code throws an exception:
DataCloneError: The object could not be cloned.
So I tried to catch the exception:
try {
self.postMessage (result);
}
catch (ex) {
if (ex instanceof DataCloneError)
self.postMessage (result.toString());
else
throw ex;
}
But this throws the following exception:
ReferenceError: DataCloneError is not defined
I am confused. How to catch the DataCloneError?
The error you receive is an instance of the DOMException interface.
To know which DOMException it is, you can check its name property.
The one of DATA_CLONE_ERROR, is "DataCloneError".
try {
postMessage( () => {} , '*' );
}
catch( err ) {
console.log( err.name === "DataCloneError" );
}
Related
I'm the author of the Dart dshell package.
https://pub.dev/packages/dshell
Dshell is a library and tooling for writing dart cli scripts.
Dshell uses waitFor to hide futures from users as they serve little use in the typical cli application.
My problem is that if a future throws an unhandled exception whilst being handled by waitFor, it essentially shuts the application down.
I need to be able to capture any exception and then let the caller decided what to do with the exception.
Here is what I've tried so far. No of the catch techniques will capture the unhandled exception:
import 'dart:async';
import 'dart:cli';
void main() {
var future = throwException();
try {
future
.catchError((Object e, StackTrace st) => print('onErrr: $e'))
.whenComplete(() => print('future completed'));
print(waitFor<int>(future));
} // on AsyncError
catch (e) {
if (e.error is Exception) {
print(e.error);
} else if (e is AsyncError) {
print('Rethrowing a non DShellException ${e}');
rethrow;
} else {
print('Rethrowing a non DShellException ${e}');
rethrow;
}
} finally {
print('waitForEx finally');
}
}
Future<int> throwException() {
var complete = Completer<int>();
Future.delayed(Duration(seconds: 2), () => throw Exception());
return complete.future;
}
The dart waitFor has a line that makes me think this may not be possible:
If the Future completes normally, its result is returned. If the Future completes with an error, the error and stack trace are wrapped in an AsyncError and thrown. If a microtask or message handler run during this call results in an unhandled exception, that exception will be propagated as though the microtask or message handler was the only Dart invocation on the stack. That is, unhandled exceptions in a microtask or message handler will skip over stacks suspended in a call to waitFor.
So I'm a little confused by the difference between a 'Future completes with an error' and 'a microtask ... results in an unhandled exception'.
The Future returned by your throwException will never complete with either a value or an error. The error thrown by the Future.delayed is an unhandled async error, it is unrelated entirely to the Future that is returned from that method. The ways to get a Future that completes with an error are:
The Future.error constructor.
Using Completer.completeError on a not yet completed Completer.
Using throw in an async method.
Using throw in a callback passed to a Future constructor, or .then.
So in your example, the Future.delayed creates a Future that will complete with an error because of the throw in the callback. Nothing is listening on this Future. There is no await, no .then or .catchError chained off of it. Once a Future completes with an error, and it has no handlers for that error, it will bubble up to the surrounding error zone. See https://dart.dev/articles/archive/zones#handling-asynchronous-errors
If you want to be able to react to unhandled errors you can use runZoned - getting the details right can be tricky. Note that it's possible to have multiple unhandled async errors resulting from running some bit of code, and that the completion of a Future does not necessarily mean that there aren't other unhandled async errors that can surface later.
From Nate Bosch I've devised a possible answer:
I hadn't realised that you can add multiple onCatchError methods to a future.
In DShell I'm passed the future so I had assumed I couldn't modify it.
So I added an onCatchError to the Future.delayed and then use the completer to pass the error back up the correct stack.
So this seems to work, I'm just uncertain if I need to actually implement a zone to cast my catch net a little further?
import 'dart:async';
import 'dart:cli';
void main() {
var future = throwExceptionV3();
try {
future
.catchError((Object e, StackTrace st) => print('onErrr: $e'))
.whenComplete(() => print('future completed'));
print(waitFor<int>(future));
} // on AsyncError
catch (e) {
if (e.error is Exception) {
print(e.error);
} else if (e is AsyncError) {
print('Rethrowing a non DShellException ${e}');
rethrow;
} else {
print('Rethrowing a non DShellException ${e}');
rethrow;
}
} finally {
print('waitForEx finally');
}
}
Future<int> throwExceptionV3() {
var complete = Completer<int>();
try
{
var future = Future.delayed(Duration(seconds: 2), () => throw Exception());
future.catchError((Object e) {
print('caught 1');
complete.completeError('caught ') ;
});
}
catch (e)
{
print ('e');
}
return complete.future;
}
Im coming from a Java background where I use the throws keyword to lead an exception to the method calling another method. How can I do that I dart?
Method called:
void _updateCurrentUserEmail() async {
await FirebaseAuth.instance
.currentUser()
.then((FirebaseUser user) {
_email = user.email;
});
}
How it is called:
try {
_updateCurrentUserEmail();
} on Exception {
return errorScreen("No User Signed In!", barActions);
}
But it seems like the Exception is not caught, because I still get a NoSuchMethodException and the errorScreen is not shown.
While you correctly used try/catch, the exception is coming from an async function that you did not await.
try/catch only catch exceptions thrown within that block. But since you wrote:
try {
doSomethingAsyncThatWillTrowLater();
} catch (e) {
}
Then the exception thrown by the async method is thrown outside of the body of try (as try finished before the async function did), and therefore not caught.
Your solution is to either use await:
try {
await doSomethingAsyncThatWillTrowLater();
} catch (e) {
}
Or use Future.catchError/Future.then:
doSomethingAsyncThatWillTrowLater().catchError((error) {
print('Error: $error');
});
From the docs,
If the catch clause does not specify a type, that clause can handle any type of thrown object:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e'); <------------------
} catch (e) {
// No specified type, handles all
print('Something really unknown: $e');
}
Change it to this:
try {
_updateCurrentUserEmail();
} on Exception catch(e){
print('error caught: $e')
}
Another way to handle error is to do the following:
void _updateCurrentUserEmail() async {
await FirebaseAuth.instance
.currentUser()
.then((FirebaseUser user) {
_email = user.email;
throw("some arbitrary error");
});
.catchError(handleError);
}
handleError(e) {
print('Error: ${e.toString()}');
}
If currentUser()’s Future completes with a value, then()’s callback fires. If code within then()’s callback throws (as it does in the example above), then()’s Future completes with an error. That error is handled by catchError().
Check the docs:
https://dart.dev/guides/libraries/futures-error-handling
Throw
Here’s an example of throwing, or raising, an exception:
throw FormatException('Expected at least 1 section');
You can also throw arbitrary objects:
throw 'Out of llamas!';
throwing an exception is an expression, you can throw exceptions in => statements, as well as anywhere else that allows expressions:
void someMethod(Point other) => throw UnimplementedError();
here is example
main() {
try {
test_age(-2);
}
catch(e) {
print('Age cannot be negative');
}
}
void test_age(int age) {
if(age<0) {
throw new FormatException();
}
}
hope it helps..
In my Flutter app I'd like to make multiple network calls simultaneously and then do something when they all have finished. For this I use Future.wait(), which does what I want. However when a call fails it throws an exception, which is somehow not caught in the exception handler (i.e. uncaught exception).
When I do await _fetchSomeData() separately (outside Future.wait()) the exception does get called by the exception handler as expected.
Future<bool> someMethod() async {
try {
var results = await Future.wait([
_fetchSomeData(),
_fetchSomeOtherData()
]);
//do some stuf when both have finished...
return true;
}
on Exception catch(e) {
//does not get triggered somehow...
_handleError(e);
return false;
}
}
What do I need to do to catch the exceptions while using Future.wait()?
Update:
I have narrowed down the issue. Turns out if you use another await statement in the method that is called by the Future.wait() it causes the issue. Here an example:
void _futureWaitTest() async {
try {
//await _someMethod(); //using this does not cause an uncaught exception, but the line below does
await Future.wait([ _someMethod(), ]);
}
on Exception catch(e) {
print(e);
}
}
Future<bool> _someMethod() async {
await Future.delayed(Duration(seconds: 0), () => print('wait')); //removing this prevents the uncaught exception
throw Exception('some exception');
}
So if you either remove the await line from _someMethod() or if you just call _someMethod() outside of Future.wait() will prevent the uncaught exception. This is most unfortunate of course, I need await for an http call... some bug in Dart?
I have the Uncaught Exceptions breakpoints enabled. If I turn this off the issue seems to be gone. Perhaps it's an issue with the debugger. I am using Visual Studio Code and the latest flutter.
What do I need to do to catch the exceptions while using Future.wait()?
What I found out when I used the same code as you the code inside of each procedure which is used in Future.wait() must be wrapped with try/catch and on catch must return Future.error(). Also eagerError must be set to true.
try {
await Future.wait([proc1, ...], eagerError: true);
} on catch(e) {
print('error: $e')
}
/// Proc 1
Future<void> proc1() async {
try {
final result = await func();
} on SomeException catch(e) {
return Future.error('proc 1 error: $');
}
}
I think you are a bit mislead by the Future.wait() naming. Future.wait() returns another future that will have a List of elements returned by each future when it completes with success.
Now since the Future.wait() is still a future. You can handle it in two ways:
Using await with try catch.
Using onError callback.
Tis will be something like
Future.wait([futureOne, futureTwo])
.then((listOfValues) {
print("ALL GOOD")
},
onError: (error) { print("Something is not ok") }
I recently stumbled across the following Dart code:
void doSomething(String url, String method) {
HttpRequest request = new HttpRequest();
request.open(method, url);
request.onLoad.listen((event) {
if(request.status < 400) {
try {
String json = request.responseText;
} catch(e) {
print("Error!");
}
} else {
print("Error! (400+)");
}
});
request.setRequestHeader("Accept", ApplicationJSON);
}
I'm wondering what the e variable is in the catch clause:
catch(e) {
...
}
Obviously its some sort of exception, but (1) why do we not need to specify its type, and (2) what could I add in there to specify its concrete type? For instance, how could I handle multiple types of possible exceptions in a similar way to catchError(someHandler, test: (e) => e is SomeException)?
Dart is an optional typed language. So the type of e is not required.
you have to use the following syntax to catch only SomeException :
try {
// ...
} on SomeException catch(e) {
//Handle exception of type SomeException
} catch(e) {
//Handle all other exceptions
}
See catch section of Dart: Up and Running.
Finally catch can accept 2 parameters ( catch(e, s) ) where the second parameter is the StackTrace.
So I'm experimenting with a try/catch clause, and I don't understand why this is happening (normal or not):
void main() {
List someList = [1,2,3];
try {
for (var x in someList) {
try {
for (var z in x) {
}
} catch(e) {
throw new Exception('inside');
}
}
} catch(e) {
throw new Exception('outside');
}
}
So you see I'm trying to do a loop inside a loop, but on purpose, someList is not a List<List>, therefore the nested loop will throw an error ('inside' error) since 1 is an int, not a List.
That's the scenario, but what happens is it throws the 'outside' error.
Is this normal? If so, where did I go wrong?
The exception you're getting is because w is undefined. If you change w to someList, then you'll get an exception for x not having an iterator, like you expect. You'll then handle that "inside" exception and immediately throw another one, which you'll catch, and then you'll throw the "outside" one, which you don't handle and will see an error for. (This might make it look like you're getting an "outside" error, but the error started on the "inside".)
This might make things clearer:
void main() {
List someList = [1,2,3];
try {
for (var x in someList) {
try {
for (var z in x) { // This throws an exception
}
} catch(e) { // Which you catch here
print(e);
print("Throwing from inside");
throw new Exception('inside'); // Now you throw another exception
}
}
} catch(e) { // Which you catch here
print(e);
print("Throwing from outside");
throw new Exception('outside'); // Now you throw a third exception
}
} // Which isn't caught, causing an
// "Unhandled exception" message