aboutsummaryrefslogtreecommitdiffstats
path: root/src/ng/rootScope.js
diff options
context:
space:
mode:
authorIgor Minar2013-08-22 02:08:41 -0700
committerIgor Minar2013-08-26 09:06:25 -0700
commit6b91aa0a18098100e5f50ea911ee135b50680d67 (patch)
tree636d84df13da7afa31b6ac9d3db45dc00e78c2d4 /src/ng/rootScope.js
parent42af8eada2803a54a98b4f792e60feb480d68a0c (diff)
downloadangular.js-6b91aa0a18098100e5f50ea911ee135b50680d67.tar.bz2
feat(Scope): async auto-flush $evalAsync queue when outside of $digest
This change causes a new $digest to be scheduled in the next tick if a task was was sent to the $evalAsync queue from outside of a $digest or an $apply. While this mode of operation is not common for most of the user code, this change means that $q promises that utilze $evalAsync queue to guarantee asynchronicity of promise apis will now also resolve outside of a $digest, which turned out to be a big pain point for some developers. The implementation ensures that we don't do more work than needed and that we coalese as much work as possible into a single $digest. The use of $browser instead of setTimeout ensures that we can mock out and control the scheduling of "auto-flush", which should in theory allow all of the existing code and tests to work without negative side-effects. Closes #3539 Closes #2438
Diffstat (limited to 'src/ng/rootScope.js')
-rw-r--r--src/ng/rootScope.js23
1 files changed, 18 insertions, 5 deletions
diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js
index d94a621d..18c54434 100644
--- a/src/ng/rootScope.js
+++ b/src/ng/rootScope.js
@@ -69,8 +69,8 @@ function $RootScopeProvider(){
return TTL;
};
- this.$get = ['$injector', '$exceptionHandler', '$parse',
- function( $injector, $exceptionHandler, $parse) {
+ this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
+ function( $injector, $exceptionHandler, $parse, $browser) {
/**
* @ngdoc function
@@ -666,13 +666,16 @@ function $RootScopeProvider(){
*
* The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
*
- * - it will execute in the current script execution context (before any DOM rendering).
- * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
- * `expression` execution.
+ * - it will execute after the function that schedule the evaluation is done running (preferably before DOM rendering).
+ * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after `expression` execution.
*
* Any exceptions from the execution of the expression are forwarded to the
* {@link ng.$exceptionHandler $exceptionHandler} service.
*
+ * __Note:__ if this function is called outside of `$digest` cycle, a new $digest cycle will be scheduled.
+ * It is however encouraged to always call code that changes the model from withing an `$apply` call.
+ * That includes code evaluated via `$evalAsync`.
+ *
* @param {(string|function())=} expression An angular expression to be executed.
*
* - `string`: execute using the rules as defined in {@link guide/expression expression}.
@@ -680,6 +683,16 @@ function $RootScopeProvider(){
*
*/
$evalAsync: function(expr) {
+ // if we are outside of an $digest loop and this is the first time we are scheduling async task also schedule
+ // async auto-flush
+ if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
+ $browser.defer(function() {
+ if ($rootScope.$$asyncQueue.length) {
+ $rootScope.$digest();
+ }
+ });
+ }
+
this.$$asyncQueue.push(expr);
},