mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 21:28:11 +02:00
Optimize iD.Connection
The big win here is using direct property accessors on node attributes rather than iteration. The rest is just micro-optimization.
This commit is contained in:
+74
-61
@@ -7,7 +7,13 @@ iD.Connection = function(context) {
|
||||
keys,
|
||||
inflight = {},
|
||||
loadedTiles = {},
|
||||
oauth = iD.OAuth(context).url(url);
|
||||
oauth = iD.OAuth(context).url(url),
|
||||
ndStr = 'nd',
|
||||
tagStr = 'tag',
|
||||
memberStr = 'member',
|
||||
nodeStr = 'node',
|
||||
wayStr = 'way',
|
||||
relationStr = 'relation';
|
||||
|
||||
function changesetUrl(changesetId) {
|
||||
return url + '/browse/changeset/' + changesetId;
|
||||
@@ -34,92 +40,99 @@ iD.Connection = function(context) {
|
||||
}
|
||||
|
||||
function getNodes(obj) {
|
||||
var nelems = obj.getElementsByTagName('nd'), nodes = new Array(nelems.length);
|
||||
for (var i = 0, l = nelems.length; i < l; i++) {
|
||||
nodes[i] = 'n' + nelems[i].attributes.ref.nodeValue;
|
||||
var elems = obj.getElementsByTagName(ndStr),
|
||||
nodes = new Array(elems.length);
|
||||
for (var i = 0, l = elems.length; i < l; i++) {
|
||||
nodes[i] = 'n' + elems[i].attributes.ref.nodeValue;
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function getTags(obj) {
|
||||
var tags = {}, tagelems = obj.getElementsByTagName('tag');
|
||||
for (var i = 0, l = tagelems.length; i < l; i++) {
|
||||
var item = tagelems[i];
|
||||
tags[item.attributes.k.nodeValue] = item.attributes.v.nodeValue;
|
||||
var elems = obj.getElementsByTagName(tagStr),
|
||||
tags = {};
|
||||
for (var i = 0, l = elems.length; i < l; i++) {
|
||||
var attrs = elems[i].attributes;
|
||||
tags[attrs.k.nodeValue] = attrs.v.nodeValue;
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
function getMembers(obj) {
|
||||
var elems = obj.getElementsByTagName('member'),
|
||||
var elems = obj.getElementsByTagName(memberStr),
|
||||
members = new Array(elems.length);
|
||||
|
||||
for (var i = 0, l = elems.length; i < l; i++) {
|
||||
var attrs = elems[i].attributes;
|
||||
members[i] = {
|
||||
id: elems[i].attributes.type.nodeValue[0] + elems[i].attributes.ref.nodeValue,
|
||||
type: elems[i].attributes.type.nodeValue,
|
||||
role: elems[i].attributes.role.nodeValue
|
||||
id: attrs.type.nodeValue[0] + attrs.ref.nodeValue,
|
||||
type: attrs.type.nodeValue,
|
||||
role: attrs.role.nodeValue
|
||||
};
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
function nodeData(obj) {
|
||||
var o = { type: 'node', tags: getTags(obj) };
|
||||
for (var i = 0, l = obj.attributes.length; i < l; i++) {
|
||||
o[obj.attributes[i].nodeName] = obj.attributes[i].nodeValue;
|
||||
}
|
||||
if (o.lon && o.lat) {
|
||||
o.loc = [parseFloat(o.lon), parseFloat(o.lat)];
|
||||
delete o.lon; delete o.lat;
|
||||
}
|
||||
o.id = iD.Entity.id.fromOSM('node', o.id);
|
||||
return new iD.Node(o);
|
||||
}
|
||||
var parsers = {
|
||||
node: function nodeData(obj) {
|
||||
var attrs = obj.attributes;
|
||||
return new iD.Node({
|
||||
id: iD.Entity.id.fromOSM(nodeStr, attrs.id.nodeValue),
|
||||
loc: [parseFloat(attrs.lon.nodeValue), parseFloat(attrs.lat.nodeValue)],
|
||||
version: attrs.version.nodeValue,
|
||||
changeset: attrs.changeset.nodeValue,
|
||||
user: attrs.user.nodeValue,
|
||||
uid: attrs.uid.nodeValue,
|
||||
visible: attrs.visible.nodeValue,
|
||||
timestamp: attrs.timestamp.nodeValue,
|
||||
tags: getTags(obj)
|
||||
});
|
||||
},
|
||||
|
||||
function wayData(obj) {
|
||||
var o = { type: 'way', nodes: getNodes(obj),
|
||||
tags: getTags(obj)
|
||||
};
|
||||
for (var i = 0, l = obj.attributes.length; i < l; i++) {
|
||||
o[obj.attributes[i].nodeName] = obj.attributes[i].nodeValue;
|
||||
}
|
||||
o.id = iD.Entity.id.fromOSM('way', o.id);
|
||||
return new iD.Way(o);
|
||||
}
|
||||
way: function wayData(obj) {
|
||||
var attrs = obj.attributes;
|
||||
return new iD.Way({
|
||||
id: iD.Entity.id.fromOSM(wayStr, attrs.id.nodeValue),
|
||||
version: attrs.version.nodeValue,
|
||||
changeset: attrs.changeset.nodeValue,
|
||||
user: attrs.user.nodeValue,
|
||||
uid: attrs.uid.nodeValue,
|
||||
visible: attrs.visible.nodeValue,
|
||||
timestamp: attrs.timestamp.nodeValue,
|
||||
tags: getTags(obj),
|
||||
nodes: getNodes(obj)
|
||||
});
|
||||
},
|
||||
|
||||
function relationData(obj) {
|
||||
var o = {
|
||||
type: 'relation', members: getMembers(obj),
|
||||
tags: getTags(obj)
|
||||
};
|
||||
for (var i = 0, l = obj.attributes.length; i < l; i++) {
|
||||
o[obj.attributes[i].nodeName] = obj.attributes[i].nodeValue;
|
||||
relation: function relationData(obj) {
|
||||
var attrs = obj.attributes;
|
||||
return new iD.Relation({
|
||||
id: iD.Entity.id.fromOSM(relationStr, attrs.id.nodeValue),
|
||||
version: attrs.version.nodeValue,
|
||||
changeset: attrs.changeset.nodeValue,
|
||||
user: attrs.user.nodeValue,
|
||||
uid: attrs.uid.nodeValue,
|
||||
visible: attrs.visible.nodeValue,
|
||||
timestamp: attrs.timestamp.nodeValue,
|
||||
tags: getTags(obj),
|
||||
members: getMembers(obj)
|
||||
});
|
||||
}
|
||||
o.id = iD.Entity.id.fromOSM('relation', o.id);
|
||||
return new iD.Relation(o);
|
||||
}
|
||||
};
|
||||
|
||||
function parse(dom) {
|
||||
if (!dom || !dom.childNodes) return new Error('Bad request');
|
||||
var root = dom.childNodes[0];
|
||||
var entities = {};
|
||||
|
||||
var root = dom.childNodes[0],
|
||||
children = root.childNodes,
|
||||
entities = {};
|
||||
|
||||
var i, o, l;
|
||||
for (i = 0, l = root.childNodes.length; i < l; i++) {
|
||||
switch(root.childNodes[i].nodeName) {
|
||||
case 'node':
|
||||
o = nodeData(root.childNodes[i]);
|
||||
entities[o.id] = o;
|
||||
break;
|
||||
case 'way':
|
||||
o = wayData(root.childNodes[i]);
|
||||
entities[o.id] = o;
|
||||
break;
|
||||
case 'relation':
|
||||
o = relationData(root.childNodes[i]);
|
||||
entities[o.id] = o;
|
||||
break;
|
||||
for (i = 0, l = children.length; i < l; i++) {
|
||||
var child = children[i],
|
||||
parser = parsers[child.nodeName];
|
||||
if (parser) {
|
||||
o = parser(child);
|
||||
entities[o.id] = o;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Node XML</title>
|
||||
<style>
|
||||
#mover {
|
||||
width:10px;
|
||||
height:10px;
|
||||
background:black;
|
||||
}
|
||||
#moved {
|
||||
width:5px;
|
||||
height:5px;
|
||||
background:red;
|
||||
}
|
||||
pre {
|
||||
position:absolute;
|
||||
top:120px;
|
||||
width:500px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='mover'>
|
||||
<div id='moved'></div>
|
||||
</div>
|
||||
<pre id='report'></pre>
|
||||
<div style="display: none" id="xml" lat="12.34" lon="12.34" version="0" user="foo">
|
||||
</div>
|
||||
<script src="benchmark.js"></script>
|
||||
<script>
|
||||
var suite = new Benchmark.Suite;
|
||||
var obj = document.getElementById("xml");
|
||||
var fns = {
|
||||
lon: function(o, v) { o.loc[0] = parseFloat(v); },
|
||||
lat: function(o, v) { o.loc[1] = parseFloat(v); }
|
||||
},
|
||||
def = function(o, v, k) { o[k] = v; };
|
||||
|
||||
// add tests
|
||||
suite
|
||||
.add('one', function() {
|
||||
var o = { type: 'node' },
|
||||
attrs = obj.attributes;
|
||||
for (var i = 0, l = attrs.length; i < l; i++) {
|
||||
var attr = attrs[i];
|
||||
o[attr.nodeName] = attr.nodeValue;
|
||||
}
|
||||
if (o.lon && o.lat) {
|
||||
o.loc = [parseFloat(o.lon), parseFloat(o.lat)];
|
||||
delete o.lon; delete o.lat;
|
||||
}
|
||||
})
|
||||
.add('two', function() {
|
||||
var o = { type: 'node', loc: [0, 0] },
|
||||
attrs = obj.attributes;
|
||||
for (var i = 0, l = attrs.length; i < l; i++) {
|
||||
var attr = attrs[i],
|
||||
k = attr.nodeName,
|
||||
v = attr.nodeValue;
|
||||
if (k === 'lon') {
|
||||
o.loc[0] = parseFloat(v);
|
||||
} else if (k === 'lat') {
|
||||
o.loc[1] = parseFloat(v);
|
||||
} else {
|
||||
o[k] = v;
|
||||
}
|
||||
}
|
||||
})
|
||||
.add('three', function() {
|
||||
var o = { type: 'node', loc: [0, 0] },
|
||||
attrs = obj.attributes;
|
||||
for (var i = 0, l = attrs.length; i < l; i++) {
|
||||
var attr = attrs[i];
|
||||
(fns[attr.nodeName] || def)(o, attr.nodeValue, attr.nodeName);
|
||||
}
|
||||
})
|
||||
.add('four', function() {
|
||||
var o = { type: 'node', loc: [0, 0] },
|
||||
attrs = obj.attributes;
|
||||
o.id = attrs.id.nodeValue;
|
||||
o.loc[0] = parseFloat(attrs.lon.nodeValue);
|
||||
o.loc[1] = parseFloat(attrs.lat.nodeValue);
|
||||
o.version = attrs.version.nodeValue;
|
||||
o.user = attrs.user.nodeValue;
|
||||
})
|
||||
// add listeners
|
||||
.on('cycle', function(event) {
|
||||
document.getElementById('report').innerHTML +=
|
||||
String(event.target) + '\n';
|
||||
})
|
||||
.on('complete', function() {
|
||||
document.getElementById('report').innerHTML +=
|
||||
'Fastest is ' + this.filter('fastest').pluck('name') + '\n';
|
||||
})
|
||||
// run async
|
||||
.run({ 'async': true });
|
||||
</script>
|
||||
</body>
|
||||
Reference in New Issue
Block a user