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

Commit 81667aa

Browse files
mvuksanochirayuk
authored andcommitted
feat(Scope): Use VmTurnZone.onScheduleMicrotask in Scope
BREAKING CHANGE: Previously a micro task registered in flush phase would cause a new digest cycle after the current digest cycle. The new behavior will cause an error. Closes #984
1 parent e76523d commit 81667aa

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

lib/core/scope.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ class RootScope extends Scope {
644644
{
645645
_zone.onTurnDone = apply;
646646
_zone.onError = (e, s, ls) => _exceptionHandler(e, s);
647+
_zone.onScheduleMicrotask = runAsync;
647648
}
648649

649650
RootScope get rootScope => this;
@@ -787,6 +788,9 @@ class RootScope extends Scope {
787788

788789
// QUEUES
789790
void runAsync(fn()) {
791+
if (_state == STATE_FLUSH || _state == STATE_FLUSH_ASSERT) {
792+
throw "Scheduling microtasks not allowed in $state state.";
793+
}
790794
var chain = new _FunctionChain(fn);
791795
if (_runAsyncHead == null) {
792796
_runAsyncHead = _runAsyncTail = chain;

lib/core/zone.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class VmTurnZone {
6060
/// an "inner" [Zone], which is a child of the outer [Zone].
6161
async.Zone _innerZone;
6262

63+
6364
/**
6465
* Associates with this
6566
*

test/core/scope_spec.dart

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,98 @@ void main() {
14401440
});
14411441
});
14421442

1443+
describe('microtask processing', () {
1444+
beforeEach((VmTurnZone zone, RootScope scope, Logger log) {
1445+
var onTurnDone = zone.onTurnDone;
1446+
zone.onTurnDone = () {
1447+
log('[');
1448+
onTurnDone();
1449+
log(']');
1450+
};
1451+
var onScheduleMicrotask = zone.onScheduleMicrotask;
1452+
zone.onScheduleMicrotask = (fn) {
1453+
log('(');
1454+
try {
1455+
onScheduleMicrotask(fn);
1456+
} catch (e) {
1457+
log('CATCH: $e');
1458+
}
1459+
log(')');
1460+
};
1461+
});
1462+
1463+
it('should schedule apply after future resolution',
1464+
async((Logger log, VmTurnZone zone, RootScope scope) {
1465+
Completer completer;
1466+
zone.run(() {
1467+
completer = new Completer();
1468+
completer.future.then((value) {
1469+
log('then($value)');
1470+
});
1471+
});
1472+
1473+
scope.runAsync(() => log('before'));
1474+
log.clear();
1475+
completer.complete('OK'); // this one causes APPLY which processe 'before'
1476+
// This one schedules work but apply already run so it does not execute.
1477+
scope.runAsync(() => log('NOT_EXECUTED'));
1478+
1479+
expect(log).toEqual(['(', ')', '[', 'before', 'then(OK)', ']']);
1480+
})
1481+
);
1482+
1483+
it('should schedule microtask to runAsync queue during digest',
1484+
async((Logger log, VmTurnZone zone, RootScope scope) {
1485+
Completer completer;
1486+
zone.run(() {
1487+
completer = new Completer();
1488+
completer.future.
1489+
then((value) {
1490+
scope.runAsync(() => log('in(${scope.state})'));
1491+
return new Future.value(value);
1492+
}).
1493+
then((value) {
1494+
log('then($value)');
1495+
});
1496+
});
1497+
log.clear();
1498+
completer.complete('OK');
1499+
expect(log).toEqual(['(', ')', '[', '(', ')', 'in(digest)', 'then(OK)', ']']);
1500+
})
1501+
);
1502+
1503+
it('should not allow microtasks in flush phase',
1504+
async((Logger log, VmTurnZone zone, RootScope scope) {
1505+
zone.run(() {
1506+
scope.domWrite(() {
1507+
return new Future.value('FAIL');
1508+
});
1509+
});
1510+
expect(log).toEqual(
1511+
['[', '(', 'CATCH: Scheduling microtasks not allowed in flush state.', ')', ']']);
1512+
})
1513+
);
1514+
1515+
it('should allow creation of Completers in flush phase',
1516+
async((Logger log, VmTurnZone zone, RootScope scope) {
1517+
Completer completer;
1518+
zone.run(() {
1519+
scope.domWrite(() {
1520+
log('new Completer');
1521+
completer = new Completer();
1522+
completer.future.then((value) {
1523+
log('then($value)');
1524+
});
1525+
});
1526+
});
1527+
log('=');
1528+
completer.complete('OK');
1529+
log(';');
1530+
expect(log).toEqual(
1531+
['[', 'new Completer', ']', '=', '(', ')', '[', 'then(OK)', ']', ';']);
1532+
})
1533+
);
1534+
});
14431535

14441536
describe('domRead/domWrite', () {
14451537
beforeEachModule((Module module) {

0 commit comments

Comments
 (0)