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

Commit ab3ae48

Browse files
mvuksanomhevery
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 ac6b56f commit ab3ae48

File tree

4 files changed

+105
-9
lines changed

4 files changed

+105
-9
lines changed

lib/core/scope.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ class RootScope extends Scope {
605605
{
606606
_zone.onTurnDone = apply;
607607
_zone.onError = (e, s, ls) => _exceptionHandler(e, s);
608+
_zone.onScheduleMicrotask = runAsync;
608609
}
609610

610611
RootScope get rootScope => this;
@@ -748,6 +749,9 @@ class RootScope extends Scope {
748749

749750
// QUEUES
750751
void runAsync(fn()) {
752+
if (_state == STATE_FLUSH || _state == STATE_FLUSH_ASSERT) {
753+
throw "Scheduling microtasks not allowed in $state state.";
754+
}
751755
var chain = new _FunctionChain(fn);
752756
if (_runAsyncHead == null) {
753757
_runAsyncHead = _runAsyncTail = chain;

lib/core/zone.dart

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

63-
ZoneScheduleMicrotask defaultOnScheduleMicrotask;
63+
ZoneScheduleMicrotask onScheduleMicrotask;
6464

6565
/**
6666
* Associates with this
@@ -115,11 +115,11 @@ class VmTurnZone {
115115

116116
_onScheduleMicrotask(async.Zone self, async.ZoneDelegate delegate,
117117
async.Zone zone, fn()) {
118-
if (defaultOnScheduleMicrotask != null) {
119-
return defaultOnScheduleMicrotask(fn);
118+
if (onScheduleMicrotask != null) {
119+
onScheduleMicrotask(fn);
120+
} else {
121+
_asyncQueue.add(() => delegate.run(zone, fn));
120122
}
121-
122-
_asyncQueue.add(() => delegate.run(zone, fn));
123123
if (_runningInTurn == 0 && !_inFinishTurn) _finishTurn(zone, delegate);
124124
}
125125

test/core/scope_spec.dart

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,98 @@ void main() {
14301430
});
14311431
});
14321432

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

14341526
describe('domRead/domWrite', () {
14351527
beforeEachModule((Module module) {

test/core/zone_spec.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ void main() {
452452
});
453453
log('onTurnDone(end)');
454454
};
455-
zone.defaultOnScheduleMicrotask = (microTaskFn) {
455+
zone.onScheduleMicrotask = (microTaskFn) {
456456
log('onScheduleMicrotask(begin)');
457457
microtaskResult = microTaskFn();
458458
log('onScheduleMicrotask(end)');
@@ -478,7 +478,7 @@ void main() {
478478
});
479479
log('onTurnDone(end)');
480480
};
481-
zone.defaultOnScheduleMicrotask = (microTaskFn) {
481+
zone.onScheduleMicrotask = (microTaskFn) {
482482
log('onScheduleMicrotask(begin)');
483483
microTaskFn();
484484
log('onScheduleMicrotask(end)');
@@ -500,7 +500,7 @@ void main() {
500500
zone.onTurnDone = () {
501501
log('onTurnDone');
502502
};
503-
zone.defaultOnScheduleMicrotask = (microTaskFn) {
503+
zone.onScheduleMicrotask = (microTaskFn) {
504504
log('onScheduleMicrotask(begin)');
505505
microTaskFn();
506506
log('onScheduleMicrotask(end)');
@@ -528,7 +528,7 @@ void main() {
528528
zone.onTurnDone = () {
529529
log('onTurnDone');
530530
};
531-
zone.defaultOnScheduleMicrotask = (microTaskFn) {
531+
zone.onScheduleMicrotask = (microTaskFn) {
532532
log('onScheduleMicrotask(begin)');
533533
microTaskFn();
534534
log('onScheduleMicrotask(end)');

0 commit comments

Comments
 (0)