Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit d1e745e

Browse files
jbdeboerchirayuk
authored andcommitted
fix(scope): Use runAsync for microtasks in digest.
BREAKING CHANGE: Microtasks scheduled in flush will process in current cycle, but they are not allowed to do model changes. Microtasks scheduled in digest will be executed in digest, counting towards the ScopeDigestTTL.
1 parent 81667aa commit d1e745e

File tree

2 files changed

+46
-16
lines changed

2 files changed

+46
-16
lines changed

lib/core/scope.dart

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -680,15 +680,8 @@ class RootScope extends Scope {
680680
ChangeLog changeLog;
681681
_scopeStats.digestStart();
682682
do {
683-
while (_runAsyncHead != null) {
684-
try {
685-
_runAsyncHead.fn();
686-
} catch (e, s) {
687-
_exceptionHandler(e, s);
688-
}
689-
_runAsyncHead = _runAsyncHead._next;
690-
}
691-
_runAsyncTail = null;
683+
684+
int asyncCount = _runAsyncFns();
692685

693686
digestTTL--;
694687
count = rootWatchGroup.detectChanges(
@@ -704,7 +697,7 @@ class RootScope extends Scope {
704697
digestLog = [];
705698
changeLog = (e, c, p) => digestLog.add('$e: $c <= $p');
706699
} else {
707-
log.add(digestLog.join(', '));
700+
log.add("${asyncCount > 0 ? 'async:$asyncCount' : ''}${digestLog.join(', ')}");
708701
digestLog.clear();
709702
}
710703
}
@@ -713,7 +706,7 @@ class RootScope extends Scope {
713706
'Last $LOG_COUNT iterations:\n${log.join('\n')}';
714707
}
715708
_scopeStats.digestLoop(count);
716-
} while (count > 0);
709+
} while (count > 0 || _runAsyncHead != null);
717710
} finally {
718711
_scopeStats.digestEnd();
719712
_transitionState(STATE_DIGEST, null);
@@ -756,7 +749,8 @@ class RootScope extends Scope {
756749
if (_domReadHead == null) _stats.domReadEnd();
757750
}
758751
_domReadTail = null;
759-
} while (_domWriteHead != null || _domReadHead != null);
752+
_runAsyncFns();
753+
} while (_domWriteHead != null || _domReadHead != null || _runAsyncHead != null);
760754
_stats.flushEnd();
761755
assert((() {
762756
_stats.flushAssertStart();
@@ -788,7 +782,7 @@ class RootScope extends Scope {
788782

789783
// QUEUES
790784
void runAsync(fn()) {
791-
if (_state == STATE_FLUSH || _state == STATE_FLUSH_ASSERT) {
785+
if (_state == STATE_FLUSH_ASSERT) {
792786
throw "Scheduling microtasks not allowed in $state state.";
793787
}
794788
var chain = new _FunctionChain(fn);
@@ -799,6 +793,21 @@ class RootScope extends Scope {
799793
}
800794
}
801795

796+
_runAsyncFns() {
797+
var count = 0;
798+
while (_runAsyncHead != null) {
799+
try {
800+
count++;
801+
_runAsyncHead.fn();
802+
} catch (e, s) {
803+
_exceptionHandler(e, s);
804+
}
805+
_runAsyncHead = _runAsyncHead._next;
806+
}
807+
_runAsyncTail = null;
808+
return count;
809+
}
810+
802811
void domWrite(fn()) {
803812
var chain = new _FunctionChain(fn);
804813
if (_domWriteHead == null) {

test/core/scope_spec.dart

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,20 @@ void main() {
12271227
});
12281228

12291229

1230+
it(r'should detect infinite digest through runAsync', (RootScope rootScope) {
1231+
rootScope.context['value'] = () { rootScope.runAsync(() {}); return 'a'; };
1232+
rootScope.watch('value()', (_, __) {});
1233+
1234+
expect(() {
1235+
rootScope.digest();
1236+
}).toThrow('Model did not stabilize in 5 digests. '
1237+
'Last 3 iterations:\n'
1238+
'async:1\n'
1239+
'async:1\n'
1240+
'async:1');
1241+
});
1242+
1243+
12301244
it(r'should always call the watchr with newVal and oldVal equal on the first run',
12311245
inject((RootScope rootScope) {
12321246
var log = [];
@@ -1500,15 +1514,22 @@ void main() {
15001514
})
15011515
);
15021516

1503-
it('should not allow microtasks in flush phase',
1517+
it('should allow microtasks in flush phase and process them immediatly',
15041518
async((Logger log, VmTurnZone zone, RootScope scope) {
1519+
scope.watch('g()', (_, __) {});
1520+
scope.context['g'] = () {
1521+
log('!');
1522+
return 0;
1523+
};
1524+
15051525
zone.run(() {
15061526
scope.domWrite(() {
1507-
return new Future.value('FAIL');
1527+
log('domWriteA');
1528+
return new Future.value(null).then((_) => scope.domWrite(() => log('domWriteB')));
15081529
});
15091530
});
15101531
expect(log).toEqual(
1511-
['[', '(', 'CATCH: Scheduling microtasks not allowed in flush state.', ')', ']']);
1532+
['[', '!', '!', 'domWriteA', '(', ')', 'domWriteB', /* assert */'!', ']']);
15121533
})
15131534
);
15141535

0 commit comments

Comments
 (0)