| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library catch_errors; |
| |
| import 'dart:async'; |
| |
| /// Runs [body] inside [runZonedGuarded]. |
| /// |
| /// Runs [body] when the returned stream is listened to. |
| /// Emits all errors, synchronous and asynchronous, |
| /// as events on the returned stream. |
| /// |
| /// **Notice**: The stream never closes. The caller should stop |
| /// listening when they're convinced there will be no later error events. |
| Stream<Object> catchErrors(void Function() body) { |
| var controller = StreamController<Object>(); |
| controller.onListen = () { |
| runZonedGuarded(body, (e, s) { |
| controller.add(e); |
| }); |
| }; |
| return controller.stream; |
| } |
| |
| /// Runs [body] inside [runZoneGuarded], [Zone.runGuarded] or [Zone.run]. |
| /// |
| /// If [onScheduleMicrotask] is provided, a custom zone is created |
| /// with a [Zone.scheduleMicrotask] which calls [onScheduleMicrotask] with |
| /// the provided callback. |
| /// |
| /// If [onError] is provided, it's used as argument to [runZonedGuarded] |
| /// or as error handler of the custom zone, and the `body` is then run |
| /// using `runGuarded`. |
| R? runZonedScheduleMicrotask<R>( |
| R body(), { |
| void Function(void Function() callback)? onScheduleMicrotask, |
| Function? onError, |
| }) { |
| if (onScheduleMicrotask == null) { |
| return runZonedGuarded(body, onError as void Function(Object, StackTrace)); |
| } |
| HandleUncaughtErrorHandler? errorHandler; |
| if (onError != null) { |
| errorHandler = |
| ( |
| Zone self, |
| ZoneDelegate parent, |
| Zone zone, |
| error, |
| StackTrace stackTrace, |
| ) { |
| try { |
| return self.parent!.runUnary( |
| onError as void Function(Object), |
| error, |
| ); |
| } catch (e, s) { |
| if (identical(e, error)) { |
| return parent.handleUncaughtError(zone, error, stackTrace); |
| } else { |
| return parent.handleUncaughtError(zone, e, s); |
| } |
| } |
| }; |
| } |
| ScheduleMicrotaskHandler? asyncHandler; |
| if (onScheduleMicrotask != null) { |
| void handle(Zone self, ZoneDelegate parent, Zone zone, Function() f) { |
| self.parent!.runUnary(onScheduleMicrotask, () => zone.runGuarded(f)); |
| } |
| |
| asyncHandler = handle; |
| } |
| ZoneSpecification specification = ZoneSpecification( |
| handleUncaughtError: errorHandler, |
| scheduleMicrotask: asyncHandler, |
| ); |
| if (onError != null) { |
| return runZoned<R>(body, zoneSpecification: specification); |
| } else { |
| Zone zone = Zone.current.fork(specification: specification); |
| return zone.run<R>(body); |
| } |
| } |