Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 8c6a817

Browse files
IgorMinarrodyhaddad
authored andcommitted
perf(Scope): change Scope#id to be a simple number
In apps that create lots of scopes (apps with large tables) the uid generation shows up in the profiler and adds a few milliseconds. Using simple counter doesn't have this overhead. I think the initial fear of overflowing and thus using string alphanum sequence is unjustified because even if an app was to create lots of scopes non-stop, you could create about 28.6 million scopes per seconds for 10 years before you would reach a number that can't be accurately represented in JS BREAKING CHANGE: Scope#$id is now of time number rather than string. Since the id is primarily being used for debugging purposes this change should not affect anyone.
1 parent 9971fbb commit 8c6a817

File tree

5 files changed

+34
-50
lines changed

5 files changed

+34
-50
lines changed

src/Angular.js

+9-25
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ var /** holds major version number for IE or NaN for real browsers */
167167
angular = window.angular || (window.angular = {}),
168168
angularModule,
169169
nodeName_,
170-
uid = ['0', '0', '0'];
170+
uid = 0;
171171

172172
/**
173173
* IE 11 changed the format of the UserAgent string.
@@ -285,33 +285,17 @@ function reverseParams(iteratorFn) {
285285
}
286286

287287
/**
288-
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
289-
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
290-
* the number string gets longer over time, and it can also overflow, where as the nextId
291-
* will grow much slower, it is a string, and it will never overflow.
288+
* A consistent way of creating unique IDs in angular.
292289
*
293-
* @returns {string} an unique alpha-numeric string
290+
* Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
291+
* we hit number precision issues in JavaScript.
292+
*
293+
* Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
294+
*
295+
* @returns {number} an unique alpha-numeric string
294296
*/
295297
function nextUid() {
296-
var index = uid.length;
297-
var digit;
298-
299-
while(index) {
300-
index--;
301-
digit = uid[index].charCodeAt(0);
302-
if (digit == 57 /*'9'*/) {
303-
uid[index] = 'A';
304-
return uid.join('');
305-
}
306-
if (digit == 90 /*'Z'*/) {
307-
uid[index] = '0';
308-
} else {
309-
uid[index] = String.fromCharCode(digit + 1);
310-
return uid.join('');
311-
}
312-
}
313-
uid.unshift('0');
314-
return uid.join('');
298+
return ++uid;
315299
}
316300

317301

test/AngularSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ describe('angular', function() {
958958

959959
while(count--) {
960960
var current = nextUid();
961-
expect(current.match(/[\d\w]+/)).toBeTruthy();
961+
expect(typeof current).toBe('number');
962962
expect(seen[current]).toBeFalsy();
963963
seen[current] = true;
964964
}

test/helpers/testabilityPatch.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ beforeEach(function() {
2424
}
2525

2626
// This resets global id counter;
27-
uid = ['0', '0', '0'];
27+
uid = 0;
2828

2929
// reset to jQuery or default to us.
3030
bindJQuery();

test/ng/compileSpec.js

+21-21
Original file line numberDiff line numberDiff line change
@@ -1885,15 +1885,15 @@ describe('$compile', function() {
18851885

18861886
it('should allow creation of new scopes', inject(function($rootScope, $compile, log) {
18871887
element = $compile('<div><span scope><a log></a></span></div>')($rootScope);
1888-
expect(log).toEqual('002; log-002-001; LOG');
1888+
expect(log).toEqual('2; log-2-1; LOG');
18891889
expect(element.find('span').hasClass('ng-scope')).toBe(true);
18901890
}));
18911891

18921892

18931893
it('should allow creation of new isolated scopes for directives', inject(
18941894
function($rootScope, $compile, log) {
18951895
element = $compile('<div><span iscope><a log></a></span></div>')($rootScope);
1896-
expect(log).toEqual('log-001-no-parent; LOG; 002');
1896+
expect(log).toEqual('log-1-no-parent; LOG; 2');
18971897
$rootScope.name = 'abc';
18981898
expect(iscope.$parent).toBe($rootScope);
18991899
expect(iscope.name).toBeUndefined();
@@ -1905,11 +1905,11 @@ describe('$compile', function() {
19051905
$httpBackend.expect('GET', 'tscope.html').respond('<a log>{{name}}; scopeId: {{$id}}</a>');
19061906
element = $compile('<div><span tscope></span></div>')($rootScope);
19071907
$httpBackend.flush();
1908-
expect(log).toEqual('log-002-001; LOG; 002');
1908+
expect(log).toEqual('log-2-1; LOG; 2');
19091909
$rootScope.name = 'Jozo';
19101910
$rootScope.$apply();
1911-
expect(element.text()).toBe('Jozo; scopeId: 002');
1912-
expect(element.find('span').scope().$id).toBe('002');
1911+
expect(element.text()).toBe('Jozo; scopeId: 2');
1912+
expect(element.find('span').scope().$id).toBe(2);
19131913
}));
19141914

19151915

@@ -1919,11 +1919,11 @@ describe('$compile', function() {
19191919
respond('<p><a log>{{name}}; scopeId: {{$id}}</a></p>');
19201920
element = $compile('<div><span trscope></span></div>')($rootScope);
19211921
$httpBackend.flush();
1922-
expect(log).toEqual('log-002-001; LOG; 002');
1922+
expect(log).toEqual('log-2-1; LOG; 2');
19231923
$rootScope.name = 'Jozo';
19241924
$rootScope.$apply();
1925-
expect(element.text()).toBe('Jozo; scopeId: 002');
1926-
expect(element.find('a').scope().$id).toBe('002');
1925+
expect(element.text()).toBe('Jozo; scopeId: 2');
1926+
expect(element.find('a').scope().$id).toBe(2);
19271927
}));
19281928

19291929

@@ -1933,12 +1933,12 @@ describe('$compile', function() {
19331933
respond('<p><a log>{{name}}; scopeId: {{$id}} |</a></p>');
19341934
element = $compile('<div><span ng-repeat="i in [1,2,3]" trscope></span></div>')($rootScope);
19351935
$httpBackend.flush();
1936-
expect(log).toEqual('log-003-002; LOG; 003; log-005-004; LOG; 005; log-007-006; LOG; 007');
1936+
expect(log).toEqual('log-3-2; LOG; 3; log-5-4; LOG; 5; log-7-6; LOG; 7');
19371937
$rootScope.name = 'Jozo';
19381938
$rootScope.$apply();
1939-
expect(element.text()).toBe('Jozo; scopeId: 003 |Jozo; scopeId: 005 |Jozo; scopeId: 007 |');
1940-
expect(element.find('p').scope().$id).toBe('003');
1941-
expect(element.find('a').scope().$id).toBe('003');
1939+
expect(element.text()).toBe('Jozo; scopeId: 3 |Jozo; scopeId: 5 |Jozo; scopeId: 7 |');
1940+
expect(element.find('p').scope().$id).toBe(3);
1941+
expect(element.find('a').scope().$id).toBe(3);
19421942
}));
19431943

19441944

@@ -1947,7 +1947,7 @@ describe('$compile', function() {
19471947
$httpBackend.expect('GET', 'tiscope.html').respond('<a log></a>');
19481948
element = $compile('<div><span tiscope></span></div>')($rootScope);
19491949
$httpBackend.flush();
1950-
expect(log).toEqual('log-002-001; LOG; 002');
1950+
expect(log).toEqual('log-2-1; LOG; 2');
19511951
$rootScope.name = 'abc';
19521952
expect(iscope.$parent).toBe($rootScope);
19531953
expect(iscope.name).toBeUndefined();
@@ -1967,7 +1967,7 @@ describe('$compile', function() {
19671967
'</b>' +
19681968
'</div>'
19691969
)($rootScope);
1970-
expect(log).toEqual('002; 003; log-003-002; LOG; log-002-001; LOG; 004; log-004-001; LOG');
1970+
expect(log).toEqual('2; 3; log-3-2; LOG; log-2-1; LOG; 4; log-4-1; LOG');
19711971
})
19721972
);
19731973

@@ -1976,7 +1976,7 @@ describe('$compile', function() {
19761976
'the scope', inject(
19771977
function($rootScope, $compile, log) {
19781978
element = $compile('<div class="scope-a; scope-b"></div>')($rootScope);
1979-
expect(log).toEqual('002; 002');
1979+
expect(log).toEqual('2; 2');
19801980
})
19811981
);
19821982

@@ -2012,15 +2012,15 @@ describe('$compile', function() {
20122012
it('should create new scope even at the root of the template', inject(
20132013
function($rootScope, $compile, log) {
20142014
element = $compile('<div scope-a></div>')($rootScope);
2015-
expect(log).toEqual('002');
2015+
expect(log).toEqual('2');
20162016
})
20172017
);
20182018

20192019

20202020
it('should create isolate scope even at the root of the template', inject(
20212021
function($rootScope, $compile, log) {
20222022
element = $compile('<div iscope></div>')($rootScope);
2023-
expect(log).toEqual('002');
2023+
expect(log).toEqual('2');
20242024
})
20252025
);
20262026

@@ -3871,8 +3871,8 @@ describe('$compile', function() {
38713871
element = $compile('<div><div trans>T:{{$parent.$id}}-{{$id}}<span>;</span></div></div>')
38723872
($rootScope);
38733873
$rootScope.$apply();
3874-
expect(element.text()).toEqual('W:001-002;T:001-003;');
3875-
expect(jqLite(element.find('span')[0]).text()).toEqual('T:001-003');
3874+
expect(element.text()).toEqual('W:1-2;T:1-3;');
3875+
expect(jqLite(element.find('span')[0]).text()).toEqual('T:1-3');
38763876
expect(jqLite(element.find('span')[1]).text()).toEqual(';');
38773877
});
38783878
});
@@ -4308,7 +4308,7 @@ describe('$compile', function() {
43084308
inject(function($compile) {
43094309
element = $compile('<div transclude>{{$id}}</div>')($rootScope);
43104310
$rootScope.$apply();
4311-
expect(element.text()).toBe($rootScope.$id);
4311+
expect(element.text()).toBe('' + $rootScope.$id);
43124312
});
43134313

43144314
});
@@ -4544,7 +4544,7 @@ describe('$compile', function() {
45444544
($rootScope);
45454545
$rootScope.$apply();
45464546
expect(log).toEqual('compile: <!-- trans: text -->; link; LOG; LOG; HIGH');
4547-
expect(element.text()).toEqual('001-002;001-003;');
4547+
expect(element.text()).toEqual('1-2;1-3;');
45484548
});
45494549
});
45504550

test/ng/directive/ngRepeatSpec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ describe('ngRepeat', function() {
976976
scope.items = [a, a, a];
977977
scope.$digest();
978978
expect($exceptionHandler.errors.shift().message).
979-
toMatch(/^\[ngRepeat:dupes\] Duplicates in a repeater are not allowed\. Use 'track by' expression to specify unique keys\. Repeater: item in items, Duplicate key: object:003/);
979+
toMatch(/^\[ngRepeat:dupes\] Duplicates in a repeater are not allowed\. Use 'track by' expression to specify unique keys\. Repeater: item in items, Duplicate key: object:3/);
980980

981981
// recover
982982
scope.items = [a];
@@ -996,7 +996,7 @@ describe('ngRepeat', function() {
996996
scope.items = [d, d, d];
997997
scope.$digest();
998998
expect($exceptionHandler.errors.shift().message).
999-
toMatch(/^\[ngRepeat:dupes\] Duplicates in a repeater are not allowed\. Use 'track by' expression to specify unique keys\. Repeater: item in items, Duplicate key: object:009/);
999+
toMatch(/^\[ngRepeat:dupes\] Duplicates in a repeater are not allowed\. Use 'track by' expression to specify unique keys\. Repeater: item in items, Duplicate key: object:9/);
10001000

10011001
// recover
10021002
scope.items = [a];

0 commit comments

Comments
 (0)