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

Commit b31d605

Browse files
committed
perf($rootScope): make postDigestQueue more efficient
1 parent 707664a commit b31d605

File tree

2 files changed

+110
-42
lines changed

2 files changed

+110
-42
lines changed

src/ng/rootScope.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ function $RootScopeProvider() {
848848

849849
clearPhase();
850850

851-
while (postDigestQueue.length) {
851+
while (!postDigestQueue.isEmpty()) {
852852
try {
853853
postDigestQueue.shift()();
854854
} catch (e) {
@@ -1306,7 +1306,7 @@ function $RootScopeProvider() {
13061306

13071307
//The internal queues. Expose them on the $rootScope for debugging/testing purposes.
13081308
var asyncQueue = $rootScope.$$asyncQueue = [];
1309-
var postDigestQueue = $rootScope.$$postDigestQueue = [];
1309+
var postDigestQueue = $rootScope.$$postDigestQueue = new Queue();
13101310
var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
13111311

13121312
return $rootScope;
@@ -1364,5 +1364,26 @@ function $RootScopeProvider() {
13641364
});
13651365
}
13661366
}
1367+
1368+
// See https://github.com/angular/angular.js/issues/14534
1369+
function Queue() {
1370+
var array = [],
1371+
head = 0;
1372+
this.push = function(item) {
1373+
array.push(item);
1374+
};
1375+
this.shift = function() {
1376+
var item = array[head];
1377+
array[head] = null;
1378+
if (++head > 100 && head * 2 >= array.length) {
1379+
array = array.slice(head);
1380+
head = 0;
1381+
}
1382+
return item;
1383+
};
1384+
this.isEmpty = function() {
1385+
return head === array.length;
1386+
};
1387+
}
13671388
}];
13681389
}

test/ng/rootScopeSpec.js

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,46 +1320,6 @@ describe('Scope', function() {
13201320
expect(externalWatchCount).toEqual(0);
13211321
}));
13221322

1323-
it('should run a $$postDigest call on all child scopes when a parent scope is digested', inject(function($rootScope) {
1324-
var parent = $rootScope.$new(),
1325-
child = parent.$new(),
1326-
count = 0;
1327-
1328-
$rootScope.$$postDigest(function() {
1329-
count++;
1330-
});
1331-
1332-
parent.$$postDigest(function() {
1333-
count++;
1334-
});
1335-
1336-
child.$$postDigest(function() {
1337-
count++;
1338-
});
1339-
1340-
expect(count).toBe(0);
1341-
$rootScope.$digest();
1342-
expect(count).toBe(3);
1343-
}));
1344-
1345-
it('should run a $$postDigest call even if the child scope is isolated', inject(function($rootScope) {
1346-
var parent = $rootScope.$new(),
1347-
child = parent.$new(true),
1348-
signature = '';
1349-
1350-
parent.$$postDigest(function() {
1351-
signature += 'A';
1352-
});
1353-
1354-
child.$$postDigest(function() {
1355-
signature += 'B';
1356-
});
1357-
1358-
expect(signature).toBe('');
1359-
$rootScope.$digest();
1360-
expect(signature).toBe('AB');
1361-
}));
1362-
13631323
it('should cause a $digest rerun', inject(function($rootScope) {
13641324
$rootScope.log = '';
13651325
$rootScope.value = 0;
@@ -1705,6 +1665,93 @@ describe('Scope', function() {
17051665
}));
17061666
});
17071667

1668+
describe('$$postDigest', function() {
1669+
it('should process callbacks as a queue (FIFO) when the scope is digested', inject(function($rootScope) {
1670+
var signature = '';
1671+
1672+
$rootScope.$$postDigest(function() {
1673+
signature += 'A';
1674+
$rootScope.$$postDigest(function() {
1675+
signature += 'D';
1676+
});
1677+
});
1678+
1679+
$rootScope.$$postDigest(function() {
1680+
signature += 'B';
1681+
});
1682+
1683+
$rootScope.$$postDigest(function() {
1684+
signature += 'C';
1685+
});
1686+
1687+
expect(signature).toBe('');
1688+
$rootScope.$digest();
1689+
expect(signature).toBe('ABCD');
1690+
}));
1691+
1692+
it('should support $apply calls nested in $$postDigest callbacks', inject(function($rootScope) {
1693+
var signature = '';
1694+
1695+
$rootScope.$$postDigest(function() {
1696+
signature += 'A';
1697+
});
1698+
1699+
$rootScope.$$postDigest(function() {
1700+
signature += 'B';
1701+
$rootScope.$apply();
1702+
expect($rootScope.$$postDigestQueue.isEmpty()).toBe(true);
1703+
signature += 'D';
1704+
});
1705+
1706+
$rootScope.$$postDigest(function() {
1707+
signature += 'C';
1708+
});
1709+
1710+
expect(signature).toBe('');
1711+
$rootScope.$digest();
1712+
expect(signature).toBe('ABCD');
1713+
}));
1714+
1715+
it('should run a $$postDigest call on all child scopes when a parent scope is digested', inject(function($rootScope) {
1716+
var parent = $rootScope.$new(),
1717+
child = parent.$new(),
1718+
count = 0;
1719+
1720+
$rootScope.$$postDigest(function() {
1721+
count++;
1722+
});
1723+
1724+
parent.$$postDigest(function() {
1725+
count++;
1726+
});
1727+
1728+
child.$$postDigest(function() {
1729+
count++;
1730+
});
1731+
1732+
expect(count).toBe(0);
1733+
$rootScope.$digest();
1734+
expect(count).toBe(3);
1735+
}));
1736+
1737+
it('should run a $$postDigest call even if the child scope is isolated', inject(function($rootScope) {
1738+
var parent = $rootScope.$new(),
1739+
child = parent.$new(true),
1740+
signature = '';
1741+
1742+
parent.$$postDigest(function() {
1743+
signature += 'A';
1744+
});
1745+
1746+
child.$$postDigest(function() {
1747+
signature += 'B';
1748+
});
1749+
1750+
expect(signature).toBe('');
1751+
$rootScope.$digest();
1752+
expect(signature).toBe('AB');
1753+
}));
1754+
});
17081755

17091756
describe('events', function() {
17101757

0 commit comments

Comments
 (0)