| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.async; | 5 part of dart.async; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A Zone represents the asynchronous version of a dynamic extent. Asynchronous | 8 * A Zone represents the asynchronous version of a dynamic extent. Asynchronous |
| 9 * callbacks are executed in the zone they have been queued in. For example, | 9 * callbacks are executed in the zone they have been queued in. For example, |
| 10 * the callback of a `future.then` is executed in the same zone as the one where | 10 * the callback of a `future.then` is executed in the same zone as the one where |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 | 230 |
| 231 _Zone oldZone = _Zone._current; | 231 _Zone oldZone = _Zone._current; |
| 232 _Zone._current = this; | 232 _Zone._current = this; |
| 233 // While we are executing the function we don't want to have other | 233 // While we are executing the function we don't want to have other |
| 234 // synchronous calls to think that they closed the zone. By incrementing | 234 // synchronous calls to think that they closed the zone. By incrementing |
| 235 // the _openCallbacks count we make sure that their test will fail. | 235 // the _openCallbacks count we make sure that their test will fail. |
| 236 // As a side effect it will make nested calls faster since they are | 236 // As a side effect it will make nested calls faster since they are |
| 237 // (probably) in the same zone and have an _openCallbacks > 0. | 237 // (probably) in the same zone and have an _openCallbacks > 0. |
| 238 bool oldIsExecuting = _isExecutingCallback; | 238 bool oldIsExecuting = _isExecutingCallback; |
| 239 _isExecutingCallback = true; | 239 _isExecutingCallback = true; |
| 240 // TODO(430): remove second try when VM bug is fixed. |
| 240 try { | 241 try { |
| 241 return fun(); | 242 try { |
| 242 } catch(e, s) { | 243 return fun(); |
| 243 if (handleUncaught) { | 244 } catch(e, s) { |
| 244 handleUncaughtError(_asyncError(e, s)); | 245 if (handleUncaught) { |
| 245 } else { | 246 handleUncaughtError(_asyncError(e, s)); |
| 246 rethrow; | 247 } else { |
| 248 rethrow; |
| 249 } |
| 247 } | 250 } |
| 248 } finally { | 251 } finally { |
| 249 _isExecutingCallback = oldIsExecuting; | 252 _isExecutingCallback = oldIsExecuting; |
| 250 _Zone._current = oldZone; | 253 _Zone._current = oldZone; |
| 251 _checkIfDone(); | 254 _checkIfDone(); |
| 252 } | 255 } |
| 253 } | 256 } |
| 254 | 257 |
| 255 /** | 258 /** |
| 256 * Runs the function and catches uncaught errors. | 259 * Runs the function and catches uncaught errors. |
| 257 * | 260 * |
| 258 * Uncaught errors are given to [handleUncaughtError]. | 261 * Uncaught errors are given to [handleUncaughtError]. |
| 259 */ | 262 */ |
| 260 _runGuarded(void fun()) { | 263 _runGuarded(void fun()) { |
| 261 _runInZone(fun, true); | 264 return _runInZone(fun, true); |
| 262 } | 265 } |
| 263 | 266 |
| 264 /** | 267 /** |
| 265 * Runs the function but doesn't catch uncaught errors. | 268 * Runs the function but doesn't catch uncaught errors. |
| 266 */ | 269 */ |
| 267 _runUnguarded(void fun()) { | 270 _runUnguarded(void fun()) { |
| 268 _runInZone(fun, false); | 271 return _runInZone(fun, false); |
| 269 } | 272 } |
| 270 | 273 |
| 271 runAsync(void fun()) { | 274 runAsync(void fun()) { |
| 272 _openCallbacks++; | 275 _openCallbacks++; |
| 273 _scheduleAsyncCallback(() { | 276 _scheduleAsyncCallback(() { |
| 274 _openCallbacks--; | 277 _openCallbacks--; |
| 275 _runGuarded(fun); | 278 _runGuarded(fun); |
| 276 }); | 279 }); |
| 277 } | 280 } |
| 278 | 281 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 */ | 341 */ |
| 339 class _WaitForCompletionZone extends _ZoneBase { | 342 class _WaitForCompletionZone extends _ZoneBase { |
| 340 final _CompletionCallback _onDone; | 343 final _CompletionCallback _onDone; |
| 341 | 344 |
| 342 _WaitForCompletionZone(_Zone parentZone, this._onDone) : super(parentZone); | 345 _WaitForCompletionZone(_Zone parentZone, this._onDone) : super(parentZone); |
| 343 | 346 |
| 344 /** | 347 /** |
| 345 * Runs the given function asynchronously. Executes the [_onDone] callback | 348 * Runs the given function asynchronously. Executes the [_onDone] callback |
| 346 * when the zone is done. | 349 * when the zone is done. |
| 347 */ | 350 */ |
| 348 void runWaitForCompletion(void fun()) { | 351 runWaitForCompletion(void fun()) { |
| 349 this._runGuarded(fun); | 352 return this._runUnguarded(fun); |
| 350 } | 353 } |
| 351 | 354 |
| 352 _dispose() { | 355 _dispose() { |
| 353 super._dispose(); | 356 super._dispose(); |
| 354 _onDone(); | 357 _onDone(); |
| 355 } | 358 } |
| 356 | 359 |
| 357 String toString() => "WaitForCompletion ${super.toString()}"; | 360 String toString() => "WaitForCompletion ${super.toString()}"; |
| 358 } | 361 } |
| 359 | 362 |
| 360 typedef bool _HandleErrorCallback(error); | 363 typedef void _HandleErrorCallback(error); |
| 361 | 364 |
| 362 /** | 365 /** |
| 363 * A zone that collects all uncaught errors and provides them in a stream. | 366 * A zone that collects all uncaught errors and provides them in a stream. |
| 364 * The stream is closed when the zone is done. | 367 * The stream is closed when the zone is done. |
| 365 */ | 368 */ |
| 366 class _CatchErrorsZone extends _WaitForCompletionZone { | 369 class _CatchErrorsZone extends _WaitForCompletionZone { |
| 367 final _HandleErrorCallback _handleError; | 370 final _HandleErrorCallback _handleError; |
| 368 | 371 |
| 369 _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone()) | 372 _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone()) |
| 370 : super(parentZone, onDone); | 373 : super(parentZone, onDone); |
| 371 | 374 |
| 372 _Zone get _errorZone => this; | 375 _Zone get _errorZone => this; |
| 373 | 376 |
| 374 handleUncaughtError(error) { | 377 handleUncaughtError(error) { |
| 375 if (!_handleError(error)) _parentZone.handleUncaughtError(error); | 378 try { |
| 379 _handleError(error); |
| 380 } catch(e, s) { |
| 381 if (identical(e, s)) { |
| 382 _parentZone.handleUncaughtError(error); |
| 383 } else { |
| 384 _parentZone.handleUncaughtError(_asyncError(e, s)); |
| 385 } |
| 386 } |
| 387 } |
| 388 |
| 389 /** |
| 390 * Runs the given function asynchronously. Executes the [_onDone] callback |
| 391 * when the zone is done. |
| 392 */ |
| 393 runWaitForCompletion(void fun()) { |
| 394 return this._runGuarded(fun); |
| 376 } | 395 } |
| 377 | 396 |
| 378 String toString() => "WithErrors ${super.toString()}"; | 397 String toString() => "WithErrors ${super.toString()}"; |
| 379 } | 398 } |
| 380 | 399 |
| 381 typedef void _TimerCallback(); | 400 typedef void _TimerCallback(); |
| 382 | 401 |
| 383 /** | 402 /** |
| 384 * A [Timer] class that takes zones into account. | 403 * A [Timer] class that takes zones into account. |
| 385 */ | 404 */ |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 _zone.executePeriodicCallbackGuarded(() { _callback(this); }); | 446 _zone.executePeriodicCallbackGuarded(() { _callback(this); }); |
| 428 } | 447 } |
| 429 | 448 |
| 430 void cancel() { | 449 void cancel() { |
| 431 if (!_isDone) _zone.cancelCallbackExpectation(); | 450 if (!_isDone) _zone.cancelCallbackExpectation(); |
| 432 _isDone = true; | 451 _isDone = true; |
| 433 _timer.cancel(); | 452 _timer.cancel(); |
| 434 } | 453 } |
| 435 } | 454 } |
| 436 | 455 |
| 437 Stream catchErrors(void body()) { | 456 /** |
| 438 _CatchErrorsZone catchErrorsZone; | 457 * Runs [body] in its own zone. |
| 439 StreamController controller; | 458 * |
| 440 | 459 * If [onError] is non-null the zone is considered an error zone. All uncaught |
| 441 void onListen() { | 460 * errors, synchronous or asynchronous, in the zone are caught and handled |
| 442 catchErrorsZone.runWaitForCompletion(body); | 461 * by the callback. |
| 462 * |
| 463 * [onDone] (if non-null) is invoked when the zone has no more outstanding |
| 464 * callbacks. |
| 465 * |
| 466 * Examples: |
| 467 * |
| 468 * runZonedExperimental(() { |
| 469 * new Future(() { throw "asynchronous error"; }); |
| 470 * }, onError: print); // Will print "asynchronous error". |
| 471 * |
| 472 * The following example prints "1", "2", "3", "4" in this order. |
| 473 * |
| 474 * runZonedExperimental(() { |
| 475 * print(1); |
| 476 * new Future.value(3).then(print); |
| 477 * }, onDone: () { print(4); }); |
| 478 * print(2); |
| 479 * |
| 480 * Errors may never cross error-zone boundaries. This is intuitive for leaving |
| 481 * a zone, but it also applies for errors that would enter an error-zone. |
| 482 * Errors that try to cross error-zone boundaries are considered uncaught. |
| 483 * |
| 484 * var future = new Future.value(499); |
| 485 * runZonedExperimental(() { |
| 486 * future = future.then((_) { throw "error in first error-zone"; }); |
| 487 * runZonedExperimental(() { |
| 488 * future = future.catchError((e) { print("Never reached!"); }); |
| 489 * }, onError: (e) { print("unused error handler"); }); |
| 490 * }, onError: (e) { print("catches error of first error-zone."); }); |
| 491 * |
| 492 */ |
| 493 runZonedExperimental(body(), { void onError(error), void onDone() }) { |
| 494 // TODO(floitsch): we probably still want to install a new Zone. |
| 495 if (onError == null && onDone == null) return body(); |
| 496 if (onError == null) { |
| 497 _WaitForCompletionZone zone = |
| 498 new _WaitForCompletionZone(_Zone._current, onDone); |
| 499 return zone.runWaitForCompletion(body); |
| 443 } | 500 } |
| 444 | 501 if (onDone == null) onDone = _nullDoneHandler; |
| 445 bool handleError(e) { | 502 _CatchErrorsZone zone = new _CatchErrorsZone(_Zone._current, onError, onDone); |
| 446 controller.add(e); | 503 return zone.runWaitForCompletion(body); |
| 447 return true; | |
| 448 } | |
| 449 | |
| 450 void onDone() { | |
| 451 controller.close(); | |
| 452 } | |
| 453 | |
| 454 catchErrorsZone = new _CatchErrorsZone(_Zone._current, handleError, onDone); | |
| 455 controller = new StreamController(onListen: onListen); | |
| 456 return controller.stream; | |
| 457 } | 504 } |
| 458 | |
| 459 Future waitForCompletion(void body()) { | |
| 460 Completer completer = new Completer.sync(); | |
| 461 _WaitForCompletionZone zone = | |
| 462 new _WaitForCompletionZone(_Zone._current, completer.complete); | |
| 463 zone.runWaitForCompletion(body); | |
| 464 return completer.future; | |
| 465 } | |
| OLD | NEW |