| 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 /** | 5 /// *Warning*: this library is **internal**, and APIs are subject to change. |
| 6 * *Warning*: this library is **internal**, and APIs are subject to change. | 6 /// |
| 7 * | 7 /// Tracks observable objects for dirty checking and testing purposes. |
| 8 * Tracks observable objects for dirty checking and testing purposes. | 8 /// |
| 9 * | 9 /// It can collect all observed objects, which can be used to trigger |
| 10 * It can collect all observed objects, which can be used to trigger predictable | 10 /// predictable delivery of all pending changes in a test, including objects |
| 11 * delivery of all pending changes in a test, including objects allocated | 11 /// allocated internally to another library, such as those in |
| 12 * internally to another library, such as those in `package:template_binding`. | 12 /// `package:template_binding`. |
| 13 */ | |
| 14 library observe.src.dirty_check; | 13 library observe.src.dirty_check; |
| 15 | 14 |
| 16 import 'dart:async'; | 15 import 'dart:async'; |
| 17 import 'package:logging/logging.dart'; | 16 import 'package:logging/logging.dart'; |
| 18 import 'package:observe/observe.dart' show Observable; | 17 import 'package:observe/observe.dart' show Observable; |
| 19 | 18 |
| 20 /** The number of active observables in the system. */ | 19 /// The number of active observables in the system. |
| 21 int get allObservablesCount => _allObservablesCount; | 20 int get allObservablesCount => _allObservablesCount; |
| 22 | 21 |
| 23 int _allObservablesCount = 0; | 22 int _allObservablesCount = 0; |
| 24 | 23 |
| 25 List<Observable> _allObservables = null; | 24 List<Observable> _allObservables = null; |
| 26 | 25 |
| 27 bool _delivering = false; | 26 bool _delivering = false; |
| 28 | 27 |
| 29 void registerObservable(Observable obj) { | 28 void registerObservable(Observable obj) { |
| 30 if (_allObservables == null) _allObservables = <Observable>[]; | 29 if (_allObservables == null) _allObservables = <Observable>[]; |
| 31 _allObservables.add(obj); | 30 _allObservables.add(obj); |
| 32 _allObservablesCount++; | 31 _allObservablesCount++; |
| 33 } | 32 } |
| 34 | 33 |
| 35 /** | 34 /// Synchronously deliver all change records for known observables. |
| 36 * Synchronously deliver all change records for known observables. | 35 /// |
| 37 * | 36 /// This will execute [Observable.deliverChanges] on objects that inherit from |
| 38 * This will execute [Observable.deliverChanges] on objects that inherit from | 37 /// [Observable]. |
| 39 * [Observable]. | |
| 40 */ | |
| 41 // Note: this is called performMicrotaskCheckpoint in change_summary.js. | 38 // Note: this is called performMicrotaskCheckpoint in change_summary.js. |
| 42 void dirtyCheckObservables() { | 39 void dirtyCheckObservables() { |
| 43 if (_delivering) return; | 40 if (_delivering) return; |
| 44 if (_allObservables == null) return; | 41 if (_allObservables == null) return; |
| 45 | 42 |
| 46 _delivering = true; | 43 _delivering = true; |
| 47 | 44 |
| 48 int cycles = 0; | 45 int cycles = 0; |
| 49 bool anyChanged = false; | 46 bool anyChanged = false; |
| 50 List debugLoop = null; | 47 List debugLoop = null; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 78 '${info[0]}, object: ${info[1]}.'); | 75 '${info[0]}, object: ${info[1]}.'); |
| 79 } | 76 } |
| 80 } | 77 } |
| 81 | 78 |
| 82 _allObservablesCount = _allObservables.length; | 79 _allObservablesCount = _allObservables.length; |
| 83 _delivering = false; | 80 _delivering = false; |
| 84 } | 81 } |
| 85 | 82 |
| 86 const MAX_DIRTY_CHECK_CYCLES = 1000; | 83 const MAX_DIRTY_CHECK_CYCLES = 1000; |
| 87 | 84 |
| 88 /** | 85 /// Log for messages produced at runtime by this library. Logging can be |
| 89 * Log for messages produced at runtime by this library. Logging can be | 86 /// configured by accessing Logger.root from the logging library. |
| 90 * configured by accessing Logger.root from the logging library. | |
| 91 */ | |
| 92 final Logger _logger = new Logger('Observable.dirtyCheck'); | 87 final Logger _logger = new Logger('Observable.dirtyCheck'); |
| 93 | 88 |
| 94 /** | 89 /// Creates a [ZoneSpecification] to set up automatic dirty checking after each |
| 95 * Creates a [ZoneSpecification] to set up automatic dirty checking after each | 90 /// batch of async operations. This ensures that change notifications are always |
| 96 * batch of async operations. This ensures that change notifications are always | 91 /// delivered. Typically used via [dirtyCheckZone]. |
| 97 * delivered. Typically used via [dirtyCheckZone]. | |
| 98 */ | |
| 99 ZoneSpecification dirtyCheckZoneSpec() { | 92 ZoneSpecification dirtyCheckZoneSpec() { |
| 100 bool pending = false; | 93 bool pending = false; |
| 101 | 94 |
| 102 enqueueDirtyCheck(ZoneDelegate parent, Zone zone) { | 95 enqueueDirtyCheck(ZoneDelegate parent, Zone zone) { |
| 103 // Only schedule one dirty check per microtask. | 96 // Only schedule one dirty check per microtask. |
| 104 if (pending) return; | 97 if (pending) return; |
| 105 | 98 |
| 106 pending = true; | 99 pending = true; |
| 107 parent.scheduleMicrotask(zone, () { | 100 parent.scheduleMicrotask(zone, () { |
| 108 pending = false; | 101 pending = false; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 126 enqueueDirtyCheck(parent, zone); | 119 enqueueDirtyCheck(parent, zone); |
| 127 return f(x); | 120 return f(x); |
| 128 }; | 121 }; |
| 129 } | 122 } |
| 130 | 123 |
| 131 return new ZoneSpecification( | 124 return new ZoneSpecification( |
| 132 registerCallback: wrapCallback, | 125 registerCallback: wrapCallback, |
| 133 registerUnaryCallback: wrapUnaryCallback); | 126 registerUnaryCallback: wrapUnaryCallback); |
| 134 } | 127 } |
| 135 | 128 |
| 136 /** | 129 /// Forks a [Zone] off the current one that does dirty-checking automatically |
| 137 * Forks a [Zone] off the current one that does dirty-checking automatically | 130 /// after each batch of async operations. Equivalent to: |
| 138 * after each batch of async operations. Equivalent to: | 131 /// |
| 139 * | 132 /// Zone.current.fork(specification: dirtyCheckZoneSpec()); |
| 140 * Zone.current.fork(specification: dirtyCheckZoneSpec()); | |
| 141 */ | |
| 142 Zone dirtyCheckZone() => Zone.current.fork(specification: dirtyCheckZoneSpec()); | 133 Zone dirtyCheckZone() => Zone.current.fork(specification: dirtyCheckZoneSpec()); |
| OLD | NEW |