Avoid using Object.keys(obj).length in hot code paths
Complexity of Object.keys(obj).length is O(n) where n is the number of object keys. Unfortunately, JavaScript have no built-in means of determining number of object keys in constant time. Therefore, we have to count object keys using separate counter variable. It may look ugly (and indeed it is), but it greatly improves smoothness and overall feel of IITC.
This commit is contained in:
parent
8563498ded
commit
55c055425b
@ -5,9 +5,9 @@
|
|||||||
window.debug = function() {}
|
window.debug = function() {}
|
||||||
|
|
||||||
window.debug.renderDetails = function() {
|
window.debug.renderDetails = function() {
|
||||||
console.log('portals: ' + Object.keys(portals).length);
|
console.log('portals: ' + window.portalsCount);
|
||||||
console.log('links: ' + Object.keys(links).length);
|
console.log('links: ' + window.linksCount);
|
||||||
console.log('fields: ' + Object.keys(fields).length);
|
console.log('fields: ' + window.fieldsCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.debug.printStackTrace = function() {
|
window.debug.printStackTrace = function() {
|
||||||
|
@ -572,7 +572,7 @@ window.getMarker = function(ent, portalLevel, latlng, team) {
|
|||||||
|
|
||||||
// renders a portal on the map from the given entity
|
// renders a portal on the map from the given entity
|
||||||
window.renderPortal = function(ent) {
|
window.renderPortal = function(ent) {
|
||||||
if(Object.keys(portals).length >= MAX_DRAWN_PORTALS && ent[0] !== selectedPortal)
|
if(window.portalsCount >= MAX_DRAWN_PORTALS && ent[0] !== selectedPortal)
|
||||||
return removeByGuid(ent[0]);
|
return removeByGuid(ent[0]);
|
||||||
|
|
||||||
// hide low level portals on low zooms
|
// hide low level portals on low zooms
|
||||||
@ -633,6 +633,7 @@ window.renderPortal = function(ent) {
|
|||||||
removeByGuid(portalResonatorGuid(portalGuid, i));
|
removeByGuid(portalResonatorGuid(portalGuid, i));
|
||||||
}
|
}
|
||||||
delete window.portals[portalGuid];
|
delete window.portals[portalGuid];
|
||||||
|
window.portalsCount --;
|
||||||
if(window.selectedPortal === portalGuid) {
|
if(window.selectedPortal === portalGuid) {
|
||||||
window.unselectOldPortal();
|
window.unselectOldPortal();
|
||||||
}
|
}
|
||||||
@ -642,6 +643,7 @@ window.renderPortal = function(ent) {
|
|||||||
// enable for debugging
|
// enable for debugging
|
||||||
if(window.portals[this.options.guid]) throw('duplicate portal detected');
|
if(window.portals[this.options.guid]) throw('duplicate portal detected');
|
||||||
window.portals[this.options.guid] = this;
|
window.portals[this.options.guid] = this;
|
||||||
|
window.portalsCount ++;
|
||||||
|
|
||||||
window.renderResonators(this.options.guid, this.options.details, this);
|
window.renderResonators(this.options.guid, this.options.details, this);
|
||||||
// handles the case where a selected portal gets removed from the
|
// handles the case where a selected portal gets removed from the
|
||||||
@ -781,7 +783,7 @@ window.resonatorsSetStyle = function(portalGuid, resoStyle, lineStyle) {
|
|||||||
|
|
||||||
// renders a link on the map from the given entity
|
// renders a link on the map from the given entity
|
||||||
window.renderLink = function(ent) {
|
window.renderLink = function(ent) {
|
||||||
if(Object.keys(links).length >= MAX_DRAWN_LINKS)
|
if(window.linksCount >= MAX_DRAWN_LINKS)
|
||||||
return removeByGuid(ent[0]);
|
return removeByGuid(ent[0]);
|
||||||
|
|
||||||
// some links are constructed from portal linkedEdges data. These have no valid 'creator' data.
|
// some links are constructed from portal linkedEdges data. These have no valid 'creator' data.
|
||||||
@ -823,11 +825,15 @@ window.renderLink = function(ent) {
|
|||||||
|
|
||||||
if(!getPaddedBounds().intersects(poly.getBounds())) return;
|
if(!getPaddedBounds().intersects(poly.getBounds())) return;
|
||||||
|
|
||||||
poly.on('remove', function() { delete window.links[this.options.guid]; });
|
poly.on('remove', function() {
|
||||||
|
delete window.links[this.options.guid];
|
||||||
|
window.linksCount--;
|
||||||
|
});
|
||||||
poly.on('add', function() {
|
poly.on('add', function() {
|
||||||
// enable for debugging
|
// enable for debugging
|
||||||
if(window.links[this.options.guid]) throw('duplicate link detected');
|
if(window.links[this.options.guid]) throw('duplicate link detected');
|
||||||
window.links[this.options.guid] = this;
|
window.links[this.options.guid] = this;
|
||||||
|
window.linksCount++;
|
||||||
this.bringToBack();
|
this.bringToBack();
|
||||||
});
|
});
|
||||||
poly.addTo(linksLayer);
|
poly.addTo(linksLayer);
|
||||||
@ -835,7 +841,7 @@ window.renderLink = function(ent) {
|
|||||||
|
|
||||||
// renders a field on the map from a given entity
|
// renders a field on the map from a given entity
|
||||||
window.renderField = function(ent) {
|
window.renderField = function(ent) {
|
||||||
if(Object.keys(fields).length >= MAX_DRAWN_FIELDS)
|
if(window.fieldsCount >= MAX_DRAWN_FIELDS)
|
||||||
return window.removeByGuid(ent[0]);
|
return window.removeByGuid(ent[0]);
|
||||||
|
|
||||||
var old = findEntityInLeaflet(fieldsLayer, window.fields, ent[0]);
|
var old = findEntityInLeaflet(fieldsLayer, window.fields, ent[0]);
|
||||||
@ -921,11 +927,15 @@ window.renderField = function(ent) {
|
|||||||
// events, thus this listener will be attached to the field. It
|
// events, thus this listener will be attached to the field. It
|
||||||
// doesn’t matter to which element these are bound since Leaflet
|
// doesn’t matter to which element these are bound since Leaflet
|
||||||
// will add/remove all elements of the LayerGroup at once.
|
// will add/remove all elements of the LayerGroup at once.
|
||||||
poly.on('remove', function() { delete window.fields[this.options.guid]; });
|
poly.on('remove', function() {
|
||||||
|
delete window.fields[this.options.guid];
|
||||||
|
window.fieldsCount--;
|
||||||
|
});
|
||||||
poly.on('add', function() {
|
poly.on('add', function() {
|
||||||
// enable for debugging
|
// enable for debugging
|
||||||
if(window.fields[this.options.guid]) console.warn('duplicate field detected');
|
if(window.fields[this.options.guid]) console.warn('duplicate field detected');
|
||||||
window.fields[this.options.guid] = f;
|
window.fields[this.options.guid] = f;
|
||||||
|
window.fieldsCount++;
|
||||||
this.bringToBack();
|
this.bringToBack();
|
||||||
});
|
});
|
||||||
f.addTo(fieldsLayer);
|
f.addTo(fieldsLayer);
|
||||||
|
@ -41,6 +41,7 @@ window.portalRenderLimit.previousMinLevel = -1;
|
|||||||
window.portalRenderLimit.previousZoomLevel = null;
|
window.portalRenderLimit.previousZoomLevel = null;
|
||||||
window.portalRenderLimit.newPortalsPerLevel = new Array(MAX_PORTAL_LEVEL + 1);
|
window.portalRenderLimit.newPortalsPerLevel = new Array(MAX_PORTAL_LEVEL + 1);
|
||||||
window.portalRenderLimit.portalsLowerThanPrevMinLv = new Array(MAX_PORTAL_LEVEL + 1);
|
window.portalRenderLimit.portalsLowerThanPrevMinLv = new Array(MAX_PORTAL_LEVEL + 1);
|
||||||
|
window.portalRenderLimit.portalsLowerThanPrevMinLvCnt = new Array(MAX_PORTAL_LEVEL + 1);
|
||||||
|
|
||||||
window.portalRenderLimit.init = function () {
|
window.portalRenderLimit.init = function () {
|
||||||
var currentZoomLevel = map.getZoom();
|
var currentZoomLevel = map.getZoom();
|
||||||
@ -72,6 +73,7 @@ window.portalRenderLimit.resetCounting = function() {
|
|||||||
window.portalRenderLimit.resetPortalsLowerThanPrevMinLv = function() {
|
window.portalRenderLimit.resetPortalsLowerThanPrevMinLv = function() {
|
||||||
for(var i = 0; i <= MAX_PORTAL_LEVEL; i++) {
|
for(var i = 0; i <= MAX_PORTAL_LEVEL; i++) {
|
||||||
portalRenderLimit.portalsLowerThanPrevMinLv[i] = {};
|
portalRenderLimit.portalsLowerThanPrevMinLv[i] = {};
|
||||||
|
portalRenderLimit.portalsLowerThanPrevMinLvCnt[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +127,7 @@ window.portalRenderLimit.splitLowLevelPortals = function(portals) {
|
|||||||
|
|
||||||
if(!portalOnMap && portalLevel < portalRenderLimit.previousMinLevel) {
|
if(!portalOnMap && portalLevel < portalRenderLimit.previousMinLevel) {
|
||||||
portalRenderLimit.portalsLowerThanPrevMinLv[portalLevel][guid] = portal;
|
portalRenderLimit.portalsLowerThanPrevMinLv[portalLevel][guid] = portal;
|
||||||
|
portalRenderLimit.portalsLowerThanPrevMinLvCnt[portalLevel]++;
|
||||||
} else {
|
} else {
|
||||||
resultPortals[guid] = portal;
|
resultPortals[guid] = portal;
|
||||||
}
|
}
|
||||||
@ -158,7 +161,7 @@ window.portalRenderLimit.setMinLevel = function() {
|
|||||||
// Find the min portal level under render limit
|
// Find the min portal level under render limit
|
||||||
while(newMinLevel > 0) {
|
while(newMinLevel > 0) {
|
||||||
var oldPortalCount = layerGroupLength(portalsLayers[newMinLevel - 1]);
|
var oldPortalCount = layerGroupLength(portalsLayers[newMinLevel - 1]);
|
||||||
var storedPortalCount = Object.keys(portalRenderLimit.portalsLowerThanPrevMinLv[newMinLevel - 1]).length;
|
var storedPortalCount = portalRenderLimit.portalsLowerThanPrevMinLvCnt[newMinLevel - 1];
|
||||||
var newPortalCount = Math.max(storedPortalCount, portalRenderLimit.newPortalsPerLevel[newMinLevel - 1]);
|
var newPortalCount = Math.max(storedPortalCount, portalRenderLimit.newPortalsPerLevel[newMinLevel - 1]);
|
||||||
|
|
||||||
totalPortalsCount += oldPortalCount + newPortalCount;
|
totalPortalsCount += oldPortalCount + newPortalCount;
|
||||||
|
@ -245,9 +245,9 @@ window.getPaddedBounds = function() {
|
|||||||
// cally detect if the render limit will be hit.
|
// cally detect if the render limit will be hit.
|
||||||
window.renderLimitReached = function(ratio) {
|
window.renderLimitReached = function(ratio) {
|
||||||
ratio = ratio || 1;
|
ratio = ratio || 1;
|
||||||
if(Object.keys(portals).length*ratio >= MAX_DRAWN_PORTALS) return true;
|
if(window.portalsCount*ratio >= MAX_DRAWN_PORTALS) return true;
|
||||||
if(Object.keys(links).length*ratio >= MAX_DRAWN_LINKS) return true;
|
if(window.linksCount*ratio >= MAX_DRAWN_LINKS) return true;
|
||||||
if(Object.keys(fields).length*ratio >= MAX_DRAWN_FIELDS) return true;
|
if(window.fieldsCount*ratio >= MAX_DRAWN_FIELDS) return true;
|
||||||
var param = { 'reached': false };
|
var param = { 'reached': false };
|
||||||
window.runHooks('checkRenderLimit', param);
|
window.runHooks('checkRenderLimit', param);
|
||||||
return param.reached;
|
return param.reached;
|
||||||
|
3
main.js
3
main.js
@ -250,8 +250,11 @@ var portalsLayers, linksLayer, fieldsLayer;
|
|||||||
// automatically kept in sync with the items on *sLayer, so never ever
|
// automatically kept in sync with the items on *sLayer, so never ever
|
||||||
// write to them.
|
// write to them.
|
||||||
window.portals = {};
|
window.portals = {};
|
||||||
|
window.portalsCount = 0;
|
||||||
window.links = {};
|
window.links = {};
|
||||||
|
window.linksCount = 0;
|
||||||
window.fields = {};
|
window.fields = {};
|
||||||
|
window.fieldsCount = 0;
|
||||||
window.resonators = {};
|
window.resonators = {};
|
||||||
|
|
||||||
// contain current status(on/off) of overlay layerGroups.
|
// contain current status(on/off) of overlay layerGroups.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user