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

Commit

Permalink
feat(scope): add support to skip auto digest in a turn
Browse files Browse the repository at this point in the history
Closes #235
  • Loading branch information
chirayuk committed Nov 19, 2013
1 parent 6ca5d73 commit 82da8e5
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
37 changes: 36 additions & 1 deletion lib/core/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class Scope implements Map {
Map<String, List<Function>> _listeners = {};
Scope _nextSibling, _prevSibling, _childHead, _childTail;
bool _isolate = false;
bool _skipAutoDigest = false;
Profiler _perf;


Expand All @@ -68,7 +69,7 @@ class Scope implements Map {
_outerAsyncQueue = [];

// Set up the zone to auto digest this scope.
_zone.onTurnDone = $digest;
_zone.onTurnDone = _autoDigestOnTurnDone;
_zone.onError = (e, s, ls) => _exceptionHandler(e, s);
}

Expand All @@ -92,6 +93,14 @@ class Scope implements Map {
}
}

_autoDigestOnTurnDone() {
if (_skipAutoDigest) {
_skipAutoDigest = false;
} else {
$digest();
}
}

_identical(a, b) =>
identical(a, b) ||
(a is String && b is String && a == b) ||
Expand Down Expand Up @@ -260,6 +269,7 @@ class Scope implements Map {
* auto-digesting scope.
*/
$$verifyDigestWillRun() {
assert(!_skipAutoDigest);
_zone.assertInTurn();
}

Expand Down Expand Up @@ -395,6 +405,31 @@ class Scope implements Map {
}


/**
* Skip running a $digest at the end of this turn.
* The primary use case is to skip the digest in the current VM turn because
* you just scheduled or are otherwise certain of an impending VM turn and the
* digest at the end of that turn is sufficient. You should be able to answer
* "No" to the question "Is there any other code that is aware that this VM
* turn occured and therefore expected a digest?". If your answer is "Yes",
* then you run the risk that the very next VM turn is not for your event and
* now that other code runs in that turn and sees stale values.
*
* You might call this function, for instance, from an event listener where,
* though the event occured, you need to wait for another event before you can
* perform something meaningful. You might schedule that other event,
* set a flag for the handler of the other event to recognize, etc. and then
* call this method to skip the digest this cycle. Note that you should call
* this function *after* you have successfully confirmed that the expected VM
* turn will occur (perhaps by scheduling it) to ensure that the digest
* actually does take place on that turn.
*/
$skipAutoDigest() {
_zone.assertInTurn();
_skipAutoDigest = true;
}


$apply([expr]) {
return _zone.run(() {
var timerId;
Expand Down
5 changes: 4 additions & 1 deletion lib/directive/ng_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ abstract class _InputTextlikeDirective {
inputElement.selectionEnd = end;
};
inputElement.onChange.listen(relaxFnArgs(processValue));
inputElement.onKeyDown.listen((e) => new async.Timer(Duration.ZERO, processValue));
inputElement.onKeyDown.listen((e) {
new async.Timer(Duration.ZERO, processValue);
scope.$skipAutoDigest();
});
}

processValue() {
Expand Down
47 changes: 46 additions & 1 deletion test/core/scope_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ import 'dart:convert' show JSON;

main() {
describe(r'Scope', () {
NgZone zone;

noop() {}

beforeEach(module(() {
return (NgZone zone) {
return (NgZone _zone) {
zone = _zone;
zone.onError = (e, s, l) => null;
};
}));
Expand Down Expand Up @@ -74,6 +79,46 @@ main() {
});


describe(r'auto digest', () {
it(r'should auto digest at the end of the turn', inject((Scope $rootScope) {
var digestedValue = 0;
$rootScope.a = 1;
$rootScope.$watch('a', (newValue, oldValue, _this) {
digestedValue = newValue;
});
expect(digestedValue).toEqual(0);
zone.run(noop);
expect(digestedValue).toEqual(1);
}));

it(r'should skip auto digest if requested', inject((Scope $rootScope) {
var digestedValue = 0;
$rootScope.a = 1;
$rootScope.$watch('a', (newValue, oldValue, _this) {
digestedValue = newValue;
});
expect(digestedValue).toEqual(0);
zone.run(() {
$rootScope.$skipAutoDigest();
});
expect(digestedValue).toEqual(0);
zone.run(noop);
expect(digestedValue).toEqual(1);
}));

it(r'should throw exception if asked to skip auto digest outside of a turn',
inject((Scope $rootScope) {
var digestedValue = 0;
$rootScope.a = 1;
$rootScope.$watch('a', (newValue, oldValue, _this) {
digestedValue = newValue;
});
expect(digestedValue).toEqual(0);
expect($rootScope.$skipAutoDigest).toThrow();
}));
});


describe(r'$watch/$digest', () {
it(r'should watch and fire on simple property change', inject((Scope $rootScope) {
var log;
Expand Down

0 comments on commit 82da8e5

Please sign in to comment.