From 93b05bdf638e1e26fa568e4fbd2c0da3b3637bcd Mon Sep 17 00:00:00 2001 From: Marko Vuksanovic Date: Tue, 29 Apr 2014 16:42:14 +1000 Subject: [PATCH] feat(VmTurnZone): VmTurnZone can handle scheduling microtasks. 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 #976 --- lib/core/zone.dart | 8 +++++ test/core/zone_spec.dart | 74 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/lib/core/zone.dart b/lib/core/zone.dart index 737e6de6c..ba63c70ff 100644 --- a/lib/core/zone.dart +++ b/lib/core/zone.dart @@ -10,6 +10,8 @@ typedef void ZoneOnTurnDone(); */ typedef void ZoneOnTurnStart(); +typedef void ZoneScheduleMicrotask(fn()); + /** * Handles an [VmTurnZone] onError event. */ @@ -58,6 +60,8 @@ class VmTurnZone { /// an "inner" [Zone], which is a child of the outer [Zone]. async.Zone _innerZone; + ZoneScheduleMicrotask onScheduleMicrotask; + /** * Associates with this * @@ -108,6 +112,10 @@ class VmTurnZone { _onScheduleMicrotask(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) { + if (onScheduleMicrotask != null) { + return onScheduleMicrotask(fn); + } + _asyncQueue.add(() => delegate.run(zone, fn)); if (_runningInTurn == 0 && !_inFinishTurn) _finishTurn(zone, delegate); } diff --git a/test/core/zone_spec.dart b/test/core/zone_spec.dart index 9e33ae62d..9845a2004 100644 --- a/test/core/zone_spec.dart +++ b/test/core/zone_spec.dart @@ -435,5 +435,79 @@ void main() { microLeap(); })).toThrow('ssertion'); // Support both dart2js and the VM with half a word. }); + + it('should allow Scope to handle scheduling of microtasks', async((Logger log) { + var microtaskResult = false; + zone.onTurnStart = () { + log('onTurnStart(begin)'); + log('onTurnStart(end)'); + }; + zone.onTurnDone = () { + log('onTurnDone(begin)'); + scheduleMicrotask(() { + log('executeMicrotask'); + return true; + }); + log('onTurnDone(end)'); + }; + zone.onScheduleMicrotask = (microTaskFn) { + log('onScheduleMicrotask(begin)'); + microtaskResult = microTaskFn(); + log('onScheduleMicrotask(end)'); + }; + zone.run(() { + log('run'); + }); + microLeap(); + + expect(log.result()).toEqual('onTurnStart(begin); onTurnStart(end); run; onTurnDone(begin); onScheduleMicrotask(begin); executeMicrotask; onScheduleMicrotask(end); onTurnDone(end)'); + expect(microtaskResult).toBeTruthy(); + })); + + it('should allow Scope to handle Future.microtask too', async((Logger log) { + zone.onTurnStart = () { + log('onTurnStart(begin)'); + log('onTurnStart(end)'); + }; + zone.onTurnDone = () { + log('onTurnDone(begin)'); + new Future.microtask(() => log('schedule from future')); + log('onTurnDone(end)'); + }; + zone.onScheduleMicrotask = (microTaskFn) { + log('onScheduleMicrotask(begin)'); + microTaskFn(); + log('onScheduleMicrotask(end)'); + }; + zone.run(() { + log('run'); + }); + microLeap(); + + expect(log.result()).toEqual('onTurnStart(begin); onTurnStart(end); run; onTurnDone(begin); onScheduleMicrotask(begin); schedule from future; onScheduleMicrotask(end); onTurnDone(end)'); + })); + + it('should allow Scope to handle Future.value too', async((Logger log) { + zone.onTurnStart = () { + log('onTurnStart(begin)'); + log('onTurnStart(end)'); + }; + zone.onTurnDone = () { + log('onTurnDone(begin)'); + new Future.value('async').then((v) => log('executed ${v}')); + log('onTurnDone(end)'); + }; + zone.onScheduleMicrotask = (microTaskFn) { + log('onScheduleMicrotask(begin)'); + microTaskFn(); + log('onScheduleMicrotask(end)'); + }; + zone.run(() { + log('run'); + }); + microLeap(); + + expect(log.result()).toEqual('onTurnStart(begin); onTurnStart(end); run; onTurnDone(begin); onScheduleMicrotask(begin); onScheduleMicrotask(end); onScheduleMicrotask(begin); executed async; onScheduleMicrotask(end); onTurnDone(end)'); + })); }); }