Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(304)

Side by Side Diff: sdk/lib/async/zone.dart

Issue 17672002: Add runAsync interceptor. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove isolate import. Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 20 matching lines...) Expand all
31 * 31 *
32 * The main purpose of this method is to allow `this` to attach debugging 32 * The main purpose of this method is to allow `this` to attach debugging
33 * information to the returned zone. 33 * information to the returned zone.
34 */ 34 */
35 _Zone fork(); 35 _Zone fork();
36 36
37 /** 37 /**
38 * Tells the zone that it needs to wait for one more callback before it is 38 * Tells the zone that it needs to wait for one more callback before it is
39 * done. 39 * done.
40 * 40 *
41 * Use [executeCallback] or [cancelCallbackExpectation] when the callback is e xecuted 41 * Use [executeCallback] or [cancelCallbackExpectation] when the callback is
42 * (or canceled). 42 * executed (or canceled).
43 */ 43 */
44 void expectCallback(); 44 void expectCallback();
45 45
46 /** 46 /**
47 * Tells the zone not to wait for a callback anymore. 47 * Tells the zone not to wait for a callback anymore.
48 * 48 *
49 * Prefer calling [executeCallback], instead. This method is mostly useful 49 * Prefer calling [executeCallback], instead. This method is mostly useful
50 * for repeated callbacks (for example with [Timer.periodic]). In this case 50 * for repeated callbacks (for example with [Timer.periodic]). In this case
51 * one should should call [expectCallback] when the repeated callback is 51 * one should should call [expectCallback] when the repeated callback is
52 * initiated, and [cancelCallbackExpectation] when the [Timer] is canceled. 52 * initiated, and [cancelCallbackExpectation] when the [Timer] is canceled.
(...skipping 20 matching lines...) Expand all
73 */ 73 */
74 void executePeriodicCallback(void fun()); 74 void executePeriodicCallback(void fun());
75 75
76 /** 76 /**
77 * Same as [executePeriodicCallback] but catches uncaught errors and gives 77 * Same as [executePeriodicCallback] but catches uncaught errors and gives
78 * them to [handleUncaughtError]. 78 * them to [handleUncaughtError].
79 */ 79 */
80 void executePeriodicCallbackGuarded(void fun()); 80 void executePeriodicCallbackGuarded(void fun());
81 81
82 /** 82 /**
83 * Runs [fun] asynchronously in this zone. 83 * Execute [fun] in `this` zone.
Lasse Reichstein Nielsen 2013/06/26 09:24:29 "fun" is untraditional naming: either "action" or
floitsch 2013/06/26 12:22:56 Done.
84 *
85 * The behavior of this method should be the same as
86 * [executePeriodicCallback] except that it can have a return value.
84 */ 87 */
85 void runAsync(void fun()); 88 runFromChildZone(fun());
89
90 /**
91 * Same as [runFromChildZone] but catches uncaught errors and gives them to
92 * [handleUncaughtError].
93 */
94 runFromChildZoneGuarded(fun());
95
96 /**
97 * Runs [fun] asynchronously in [zone].
98 */
99 void runAsync(void fun(), _Zone zone);
86 100
87 /** 101 /**
88 * Creates a Timer where the callback is executed in this zone. 102 * Creates a Timer where the callback is executed in this zone.
89 */ 103 */
90 Timer createTimer(Duration duration, void callback()); 104 Timer createTimer(Duration duration, void callback());
91 105
92 /** 106 /**
93 * Creates a periodic Timer where the callback is executed in this zone. 107 * Creates a periodic Timer where the callback is executed in this zone.
94 */ 108 */
95 Timer createPeriodicTimer(Duration duration, void callback(Timer timer)); 109 Timer createPeriodicTimer(Duration duration, void callback(Timer timer));
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 } 227 }
214 228
215 /** 229 /**
216 * Same as [executePeriodicCallback] but catches uncaught errors and gives 230 * Same as [executePeriodicCallback] but catches uncaught errors and gives
217 * them to [handleUncaughtError]. 231 * them to [handleUncaughtError].
218 */ 232 */
219 void executePeriodicCallbackGuarded(void fun()) { 233 void executePeriodicCallbackGuarded(void fun()) {
220 this._runGuarded(fun); 234 this._runGuarded(fun);
221 } 235 }
222 236
237 runFromChildZone(fun()) => this._runUnguarded(fun);
238 runFromChildZoneGuarded(fun()) => this._runGuarded(fun);
239
223 _runInZone(fun(), bool handleUncaught) { 240 _runInZone(fun(), bool handleUncaught) {
224 if (identical(_Zone._current, this) 241 if (identical(_Zone._current, this)
225 && !handleUncaught 242 && !handleUncaught
226 && _isExecutingCallback) { 243 && _isExecutingCallback) {
227 // No need to go through a try/catch. 244 // No need to go through a try/catch.
228 return fun(); 245 return fun();
229 } 246 }
230 247
231 _Zone oldZone = _Zone._current; 248 _Zone oldZone = _Zone._current;
232 _Zone._current = this; 249 _Zone._current = this;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 return _runInZone(fun, true); 281 return _runInZone(fun, true);
265 } 282 }
266 283
267 /** 284 /**
268 * Runs the function but doesn't catch uncaught errors. 285 * Runs the function but doesn't catch uncaught errors.
269 */ 286 */
270 _runUnguarded(void fun()) { 287 _runUnguarded(void fun()) {
271 return _runInZone(fun, false); 288 return _runInZone(fun, false);
272 } 289 }
273 290
274 runAsync(void fun()) { 291 runAsync(void fun(), _Zone zone) => _parentZone.runAsync(fun, zone);
275 _openCallbacks++;
276 _scheduleAsyncCallback(() {
277 _openCallbacks--;
278 _runGuarded(fun);
279 });
280 }
281 292
293 // TODO(floitsch): the zone should just forward to the parent zone. The
294 // default zone should then create the _ZoneTimer.
282 Timer createTimer(Duration duration, void callback()) { 295 Timer createTimer(Duration duration, void callback()) {
283 return new _ZoneTimer(this, duration, callback); 296 return new _ZoneTimer(this, duration, callback);
284 } 297 }
285 298
299 // TODO(floitsch): the zone should just forward to the parent zone. The
300 // default zone should then create the _ZoneTimer.
286 Timer createPeriodicTimer(Duration duration, void callback(Timer timer)) { 301 Timer createPeriodicTimer(Duration duration, void callback(Timer timer)) {
287 return new _PeriodicZoneTimer(this, duration, callback); 302 return new _PeriodicZoneTimer(this, duration, callback);
288 } 303 }
289 304
290 void _addChild(_Zone child) { 305 void _addChild(_Zone child) {
306 // TODO(floitsch): the zone should just increment a counter, but not keep
307 // a reference to the child.
291 _children.add(child); 308 _children.add(child);
292 } 309 }
293 310
294 void _removeChild(_Zone child) { 311 void _removeChild(_Zone child) {
295 assert(!_children.isEmpty); 312 assert(!_children.isEmpty);
296 // Children are usually added and removed fifo or filo. 313 // Children are usually added and removed fifo or filo.
297 if (identical(_children.last, child)) { 314 if (identical(_children.last, child)) {
298 _children.length--; 315 _children.length--;
299 _checkIfDone(); 316 _checkIfDone();
300 return; 317 return;
(...skipping 24 matching lines...) Expand all
325 _scheduleAsyncCallback(() { 342 _scheduleAsyncCallback(() {
326 print("Uncaught Error: ${error}"); 343 print("Uncaught Error: ${error}");
327 var trace = getAttachedStackTrace(error); 344 var trace = getAttachedStackTrace(error);
328 _attachStackTrace(error, null); 345 _attachStackTrace(error, null);
329 if (trace != null) { 346 if (trace != null) {
330 print("Stack Trace:\n$trace\n"); 347 print("Stack Trace:\n$trace\n");
331 } 348 }
332 throw error; 349 throw error;
333 }); 350 });
334 } 351 }
352
353 void runAsync(void fun(), _Zone zone) {
354 if (identical(this, zone)) {
355 // No need to go through the zone when it's the default zone anyways.
356 _scheduleAsyncCallback(fun);
357 return;
358 }
359 zone.expectCallback();
360 _scheduleAsyncCallback(() {
361 zone.executeCallbackGuarded(fun);
362 });
363 }
335 } 364 }
336 365
337 typedef void _CompletionCallback(); 366 typedef void _CompletionCallback();
338 367
339 /** 368 /**
340 * A zone that executes a callback when the zone is dead. 369 * A zone that executes a callback when the zone is dead.
341 */ 370 */
342 class _WaitForCompletionZone extends _ZoneBase { 371 class _WaitForCompletionZone extends _ZoneBase {
343 final _CompletionCallback _onDone; 372 final _CompletionCallback _onDone;
344 373
(...skipping 18 matching lines...) Expand all
363 typedef void _HandleErrorCallback(error); 392 typedef void _HandleErrorCallback(error);
364 393
365 /** 394 /**
366 * A zone that collects all uncaught errors and provides them in a stream. 395 * A zone that collects all uncaught errors and provides them in a stream.
367 * The stream is closed when the zone is done. 396 * The stream is closed when the zone is done.
368 */ 397 */
369 class _CatchErrorsZone extends _WaitForCompletionZone { 398 class _CatchErrorsZone extends _WaitForCompletionZone {
370 final _HandleErrorCallback _handleError; 399 final _HandleErrorCallback _handleError;
371 400
372 _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone()) 401 _CatchErrorsZone(_Zone parentZone, this._handleError, void onDone())
373 : super(parentZone, onDone); 402 : super(parentZone, onDone);
374 403
375 _Zone get _errorZone => this; 404 _Zone get _errorZone => this;
376 405
377 handleUncaughtError(error) { 406 handleUncaughtError(error) {
378 try { 407 try {
379 _handleError(error); 408 _handleError(error);
380 } catch(e, s) { 409 } catch(e, s) {
381 if (identical(e, s)) { 410 if (identical(e, s)) {
382 _parentZone.handleUncaughtError(error); 411 _parentZone.handleUncaughtError(error);
383 } else { 412 } else {
384 _parentZone.handleUncaughtError(_asyncError(e, s)); 413 _parentZone.handleUncaughtError(_asyncError(e, s));
385 } 414 }
386 } 415 }
387 } 416 }
388 417
389 /** 418 /**
390 * Runs the given function asynchronously. Executes the [_onDone] callback 419 * Runs the given function asynchronously. Executes the [_onDone] callback
391 * when the zone is done. 420 * when the zone is done.
392 */ 421 */
393 runWaitForCompletion(void fun()) { 422 runWaitForCompletion(void fun()) {
394 return this._runGuarded(fun); 423 return this._runGuarded(fun);
395 } 424 }
396 425
397 String toString() => "WithErrors ${super.toString()}"; 426 String toString() => "CatchErrors ${super.toString()}";
427 }
428
429 typedef void _RunAsyncInterceptor(void callback());
430
431 class _RunAsyncZone extends _ZoneBase {
432 final _RunAsyncInterceptor _runAsyncInterceptor;
433
434 _RunAsyncZone(_Zone parentZone, this._runAsyncInterceptor)
435 : super(parentZone);
436
437 void runAsync(void callback(), _Zone zone) {
438 zone.expectCallback();
439 _parentZone.runFromChildZone(() {
440 _runAsyncInterceptor(() => zone.executeCallbackGuarded(callback));
441 });
442 }
398 } 443 }
399 444
400 typedef void _TimerCallback(); 445 typedef void _TimerCallback();
401 446
402 /** 447 /**
403 * A [Timer] class that takes zones into account. 448 * A [Timer] class that takes zones into account.
404 */ 449 */
405 class _ZoneTimer implements Timer { 450 class _ZoneTimer implements Timer {
406 final _Zone _zone; 451 final _Zone _zone;
407 final _TimerCallback _callback; 452 final _TimerCallback _callback;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 } 498 }
454 } 499 }
455 500
456 /** 501 /**
457 * Runs [body] in its own zone. 502 * Runs [body] in its own zone.
458 * 503 *
459 * If [onError] is non-null the zone is considered an error zone. All uncaught 504 * If [onError] is non-null the zone is considered an error zone. All uncaught
460 * errors, synchronous or asynchronous, in the zone are caught and handled 505 * errors, synchronous or asynchronous, in the zone are caught and handled
461 * by the callback. 506 * by the callback.
462 * 507 *
463 * [onDone] (if non-null) is invoked when the zone has no more outstanding 508 * [onDone] (if non-null) is invoked when the zone has no more outstanding
Lasse Reichstein Nielsen 2013/06/26 09:24:29 [onDone] -> The [onDone] callback (avoid initial l
floitsch 2013/06/26 12:22:56 Done.
464 * callbacks. 509 * callbacks.
465 * 510 *
511 * [onRunAsync] (if non-null) is invoked when the [body] executes [runAsync].
Lasse Reichstein Nielsen 2013/06/26 09:24:29 Ditto.
floitsch 2013/06/26 12:22:56 Done.
512 * The handler is invoked in the outer zone and can therefore execute
513 * [runAsync] without invoking itself. The given callback must be executed
514 * eventually. Otherwise the nested zone will not complete. It must be
515 * executed only once.
516 *
466 * Examples: 517 * Examples:
467 * 518 *
468 * runZonedExperimental(() { 519 * runZonedExperimental(() {
469 * new Future(() { throw "asynchronous error"; }); 520 * new Future(() { throw "asynchronous error"; });
470 * }, onError: print); // Will print "asynchronous error". 521 * }, onError: print); // Will print "asynchronous error".
471 * 522 *
472 * The following example prints "1", "2", "3", "4" in this order. 523 * The following example prints "1", "2", "3", "4" in this order.
473 * 524 *
474 * runZonedExperimental(() { 525 * runZonedExperimental(() {
475 * print(1); 526 * print(1);
476 * new Future.value(3).then(print); 527 * new Future.value(3).then(print);
477 * }, onDone: () { print(4); }); 528 * }, onDone: () { print(4); });
478 * print(2); 529 * print(2);
479 * 530 *
480 * Errors may never cross error-zone boundaries. This is intuitive for leaving 531 * 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. 532 * 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. 533 * Errors that try to cross error-zone boundaries are considered uncaught.
483 * 534 *
484 * var future = new Future.value(499); 535 * var future = new Future.value(499);
485 * runZonedExperimental(() { 536 * runZonedExperimental(() {
486 * future = future.then((_) { throw "error in first error-zone"; }); 537 * future = future.then((_) { throw "error in first error-zone"; });
487 * runZonedExperimental(() { 538 * runZonedExperimental(() {
488 * future = future.catchError((e) { print("Never reached!"); }); 539 * future = future.catchError((e) { print("Never reached!"); });
489 * }, onError: (e) { print("unused error handler"); }); 540 * }, onError: (e) { print("unused error handler"); });
490 * }, onError: (e) { print("catches error of first error-zone."); }); 541 * }, onError: (e) { print("catches error of first error-zone."); });
491 * 542 *
543 * The following example prints the stack trace whenever a callback is
544 * registered using [runAsync] (which is also used by [Completer]s and
545 * [StreamController]s.
546 *
547 * printStackTrace() { try { throw 0; } catch(e, s) { print(s); } }
548 * runZonedExperimental(body, onRunAsync: (callback) {
549 * printStackTrace();
550 * runAsync(callback);
551 * });
492 */ 552 */
493 runZonedExperimental(body(), { void onError(error), void onDone() }) { 553 runZonedExperimental(body(),
554 { void onRunAsync(void callback()),
555 void onError(error),
556 void onDone() }) {
557 if (onRunAsync != null) {
558 _RunAsyncZone zone = new _RunAsyncZone(_Zone._current, onRunAsync);
559 return zone._runUnguarded(() {
560 return runZonedExperimental(body, onError: onError, onDone: onDone);
561 });
562 }
563
494 // TODO(floitsch): we probably still want to install a new Zone. 564 // TODO(floitsch): we probably still want to install a new Zone.
495 if (onError == null && onDone == null) return body(); 565 if (onError == null && onDone == null) return body();
496 if (onError == null) { 566 if (onError == null) {
497 _WaitForCompletionZone zone = 567 _WaitForCompletionZone zone =
498 new _WaitForCompletionZone(_Zone._current, onDone); 568 new _WaitForCompletionZone(_Zone._current, onDone);
499 return zone.runWaitForCompletion(body); 569 return zone.runWaitForCompletion(body);
500 } 570 }
501 if (onDone == null) onDone = _nullDoneHandler; 571 if (onDone == null) onDone = _nullDoneHandler;
502 _CatchErrorsZone zone = new _CatchErrorsZone(_Zone._current, onError, onDone); 572 _CatchErrorsZone zone = new _CatchErrorsZone(_Zone._current, onError, onDone);
503 return zone.runWaitForCompletion(body); 573 return zone.runWaitForCompletion(body);
504 } 574 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698