| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 |  | 
| 3 // BSD-style license that can be found in the LICENSE file. |  | 
| 4 |  | 
| 5 part of dart.async; |  | 
| 6 |  | 
| 7 typedef void _AsyncCallback(); |  | 
| 8 |  | 
| 9 class _AsyncCallbackEntry { |  | 
| 10   final _AsyncCallback callback; |  | 
| 11   _AsyncCallbackEntry next; |  | 
| 12   _AsyncCallbackEntry(this.callback); |  | 
| 13 } |  | 
| 14 |  | 
| 15 /** Head of single linked list of pending callbacks. */ |  | 
| 16 _AsyncCallbackEntry _nextCallback; |  | 
| 17 /** Tail of single linked list of pending callbacks. */ |  | 
| 18 _AsyncCallbackEntry _lastCallback; |  | 
| 19 /** |  | 
| 20  * Tail of priority callbacks added by the currently executing callback. |  | 
| 21  * |  | 
| 22  * Priority callbacks are put at the beginning of the |  | 
| 23  * callback queue, so that if one callback schedules more than one |  | 
| 24  * priority callback, they are still enqueued in scheduling order. |  | 
| 25  */ |  | 
| 26 _AsyncCallbackEntry _lastPriorityCallback; |  | 
| 27 /** |  | 
| 28  * Whether we are currently inside the callback loop. |  | 
| 29  * |  | 
| 30  * If we are inside the loop, we never need to schedule the loop, |  | 
| 31  * even if adding a first element. |  | 
| 32  */ |  | 
| 33 bool _isInCallbackLoop = false; |  | 
| 34 |  | 
| 35 void _microtaskLoop() { |  | 
| 36   while (_nextCallback != null) { |  | 
| 37     _lastPriorityCallback = null; |  | 
| 38     _AsyncCallbackEntry entry = _nextCallback; |  | 
| 39     _nextCallback = entry.next; |  | 
| 40     if (_nextCallback == null) _lastCallback = null; |  | 
| 41     (entry.callback)(); |  | 
| 42   } |  | 
| 43 } |  | 
| 44 |  | 
| 45 void _startMicrotaskLoop() { |  | 
| 46   _isInCallbackLoop = true; |  | 
| 47   try { |  | 
| 48     // Moved to separate function because try-finally prevents |  | 
| 49     // good optimization. |  | 
| 50     _microtaskLoop(); |  | 
| 51   } finally { |  | 
| 52     _lastPriorityCallback = null; |  | 
| 53     _isInCallbackLoop = false; |  | 
| 54     if (_nextCallback != null) { |  | 
| 55       _AsyncRun._scheduleImmediate(_startMicrotaskLoop); |  | 
| 56     } |  | 
| 57   } |  | 
| 58 } |  | 
| 59 |  | 
| 60 /** |  | 
| 61  * Schedules a callback to be called as a microtask. |  | 
| 62  * |  | 
| 63  * The microtask is called after all other currently scheduled |  | 
| 64  * microtasks, but as part of the current system event. |  | 
| 65  */ |  | 
| 66 void _scheduleAsyncCallback(_AsyncCallback callback) { |  | 
| 67   _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback); |  | 
| 68   if (_nextCallback == null) { |  | 
| 69     _nextCallback = _lastCallback = newEntry; |  | 
| 70     if (!_isInCallbackLoop) { |  | 
| 71       _AsyncRun._scheduleImmediate(_startMicrotaskLoop); |  | 
| 72     } |  | 
| 73   } else { |  | 
| 74     _lastCallback.next = newEntry; |  | 
| 75     _lastCallback = newEntry; |  | 
| 76   } |  | 
| 77 } |  | 
| 78 |  | 
| 79 /** |  | 
| 80  * Schedules a callback to be called before all other currently scheduled ones. |  | 
| 81  * |  | 
| 82  * This callback takes priority over existing scheduled callbacks. |  | 
| 83  * It is only used internally to give higher priority to error reporting. |  | 
| 84  * |  | 
| 85  * Is always run in the root zone. |  | 
| 86  */ |  | 
| 87 void _schedulePriorityAsyncCallback(_AsyncCallback callback) { |  | 
| 88   if (_nextCallback == null) { |  | 
| 89     _scheduleAsyncCallback(callback); |  | 
| 90     _lastPriorityCallback = _lastCallback; |  | 
| 91     return; |  | 
| 92   } |  | 
| 93   _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback); |  | 
| 94   if (_lastPriorityCallback == null) { |  | 
| 95     entry.next = _nextCallback; |  | 
| 96     _nextCallback = _lastPriorityCallback = entry; |  | 
| 97   } else { |  | 
| 98     entry.next = _lastPriorityCallback.next; |  | 
| 99     _lastPriorityCallback.next = entry; |  | 
| 100     _lastPriorityCallback = entry; |  | 
| 101     if (entry.next == null) { |  | 
| 102       _lastCallback = entry; |  | 
| 103     } |  | 
| 104   } |  | 
| 105 } |  | 
| 106 |  | 
| 107 /** |  | 
| 108  * Runs a function asynchronously. |  | 
| 109  * |  | 
| 110  * Callbacks registered through this function are always executed in order and |  | 
| 111  * are guaranteed to run before other asynchronous events (like [Timer] events, |  | 
| 112  * or DOM events). |  | 
| 113  * |  | 
| 114  * **Warning:** it is possible to starve the DOM by registering asynchronous |  | 
| 115  * callbacks through this method. For example the following program runs |  | 
| 116  * the callbacks without ever giving the Timer callback a chance to execute: |  | 
| 117  * |  | 
| 118  *     main() { |  | 
| 119  *       Timer.run(() { print("executed"); });  // Will never be executed. |  | 
| 120  *       foo() { |  | 
| 121  *         scheduleMicrotask(foo);  // Schedules [foo] in front of other events. |  | 
| 122  *       } |  | 
| 123  *       foo(); |  | 
| 124  *     } |  | 
| 125  * |  | 
| 126  * ## Other resources |  | 
| 127  * |  | 
| 128  * * [The Event Loop and Dart](https://www.dartlang.org/articles/event-loop/): |  | 
| 129  * Learn how Dart handles the event queue and microtask queue, so you can write |  | 
| 130  * better asynchronous code with fewer surprises. |  | 
| 131  */ |  | 
| 132 void scheduleMicrotask(void callback()) { |  | 
| 133   _Zone currentZone = Zone.current; |  | 
| 134   if (identical(_ROOT_ZONE, currentZone)) { |  | 
| 135     // No need to bind the callback. We know that the root's scheduleMicrotask |  | 
| 136     // will be invoked in the root zone. |  | 
| 137     _rootScheduleMicrotask(null, null, _ROOT_ZONE, callback); |  | 
| 138     return; |  | 
| 139   } |  | 
| 140   _ZoneFunction implementation = currentZone._scheduleMicrotask; |  | 
| 141   if (identical(_ROOT_ZONE, implementation.zone) && |  | 
| 142       _ROOT_ZONE.inSameErrorZone(currentZone)) { |  | 
| 143     _rootScheduleMicrotask(null, null, currentZone, |  | 
| 144                            currentZone.registerCallback(callback)); |  | 
| 145     return; |  | 
| 146   } |  | 
| 147   Zone.current.scheduleMicrotask( |  | 
| 148       Zone.current.bindCallback(callback, runGuarded: true)); |  | 
| 149 } |  | 
| 150 |  | 
| 151 class _AsyncRun { |  | 
| 152   /** Schedule the given callback before any other event in the event-loop. */ |  | 
| 153   external static void _scheduleImmediate(void callback()); |  | 
| 154 } |  | 
| OLD | NEW | 
|---|