Skip to content

Commit

Permalink
feat(VmTurnZone): VmTurnZone can handle scheduling microtasks.
Browse files Browse the repository at this point in the history
To customize how VmTurnZone handles microtasks assign a function to
VmTurnZone.onScheduleMicrotask. This method will then be used whenever
a microtask is scheduled instead of the default implementation.

Closes dart-archive#976
  • Loading branch information
mvuksano committed Apr 30, 2014
1 parent 40563c8 commit 88e008e
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
8 changes: 8 additions & 0 deletions lib/core/zone.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ typedef void ZoneOnTurnDone();
*/
typedef void ZoneOnTurnStart();

typedef void ZoneScheduleMicrotask(fn());

/**
* Handles a [VmTurnZone] onError event.
*/
Expand Down Expand Up @@ -58,6 +60,8 @@ class VmTurnZone {
/// an "inner" [Zone], which is a child of the outer [Zone].
async.Zone _innerZone;

ZoneScheduleMicrotask defaultOnScheduleMicrotask;

/**
* Associates with this
*
Expand Down Expand Up @@ -111,6 +115,10 @@ class VmTurnZone {

_onScheduleMicrotask(async.Zone self, async.ZoneDelegate delegate,
async.Zone zone, fn()) {
if (defaultOnScheduleMicrotask != null) {
return defaultOnScheduleMicrotask(fn);
}

_asyncQueue.add(() => delegate.run(zone, fn));
if (_runningInTurn == 0 && !_inFinishTurn) _finishTurn(zone, delegate);
}
Expand Down
108 changes: 108 additions & 0 deletions test/core/zone_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ library zone_spec;
import '../_specs.dart';

import 'dart:async';
import 'dart:mirrors';

void main() {
describe('zone', () {
Expand Down Expand Up @@ -435,5 +436,112 @@ void main() {
microLeap();
})).toThrow('ssertion'); // Support both dart2js and the VM with half a word.
});

group('microtask scheduler', () {

it('should execute microtask scheduled in onTurnDone before onTurnDone is complete',
async((Logger log) {
var microtaskResult = false;
zone.onTurnStart = () {
log('onTurnStart');
};
zone.onTurnDone = () {
log('onTurnDone(begin)');
scheduleMicrotask(() {
log('executeMicrotask');
return true;
});
log('onTurnDone(end)');
};
zone.defaultOnScheduleMicrotask = (microTaskFn) {
log('onScheduleMicrotask(begin)');
microtaskResult = microTaskFn();
log('onScheduleMicrotask(end)');
};
zone.run(() {
log('run');
});

expect(log.result()).toEqual('onTurnStart; run; onTurnDone(begin); '
'onScheduleMicrotask(begin); executeMicrotask; onScheduleMicrotask(end); onTurnDone(end)'
);
expect(microtaskResult).toBeTruthy();
}));

it('should work with future scheduled in onTurnDone', async((Logger log) {
zone.onTurnStart = () {
log('onTurnStart');
};
zone.onTurnDone = () {
log('onTurnDone(begin)');
new Future.value('async').then((v) {
log('executed ${v}');
});
log('onTurnDone(end)');
};
zone.defaultOnScheduleMicrotask = (microTaskFn) {
log('onScheduleMicrotask(begin)');
microTaskFn();
log('onScheduleMicrotask(end)');
};
zone.run(() {
log('run');
});

expect(log.result()).toEqual('onTurnStart; run; onTurnDone(begin); '
'onScheduleMicrotask(begin); onScheduleMicrotask(end); onScheduleMicrotask(begin);'
' executed async; onScheduleMicrotask(end); onTurnDone(end)');
}));

it('should execute microtask scheduled in run before onTurnDone starts',
async((Logger log) {
zone.onTurnStart = () {
log('onTurnStart');
};
zone.onTurnDone = () {
log('onTurnDone');
};
zone.defaultOnScheduleMicrotask = (microTaskFn) {
log('onScheduleMicrotask(begin)');
microTaskFn();
log('onScheduleMicrotask(end)');
};
zone.run(() {
log('run');
scheduleMicrotask(() {
log('executeMicrotask');
return true;
});
});

expect(log.result()).toEqual('onTurnStart; run; onScheduleMicrotask(begin);'
' executeMicrotask; onScheduleMicrotask(end); onTurnDone');
}));

it('should execute microtask scheduled in onTurnStart before run',
async((Logger log) {
zone.onTurnStart = () {
log('onTurnStart');
scheduleMicrotask(() {
log('executeMicrotask');
});
};
zone.onTurnDone = () {
log('onTurnDone');
};
zone.defaultOnScheduleMicrotask = (microTaskFn) {
log('onScheduleMicrotask(begin)');
microTaskFn();
log('onScheduleMicrotask(end)');
};
zone.run(() {
log('run');
});

expect(log.result()).toEqual('onTurnStart; onScheduleMicrotask(begin); executeMicrotask;'
' onScheduleMicrotask(end); run; onTurnDone');
}));

});
});
}

0 comments on commit 88e008e

Please sign in to comment.