diff --git a/index.html b/index.html
index 640dfa51a..4cf24afff 100644
--- a/index.html
+++ b/index.html
@@ -23,6 +23,7 @@
+
diff --git a/js/id/connection.js b/js/id/connection.js
index d24aeffc1..0c10d37d3 100644
--- a/js/id/connection.js
+++ b/js/id/connection.js
@@ -149,10 +149,6 @@ iD.Connection = function() {
return true;
}
- function apiRequestExtent(extent) {
- bboxFromAPI(extent, event.load);
- }
-
function loadTiles(projection) {
var scaleExtent = [16, 16],
s = projection.scale(),
@@ -176,10 +172,20 @@ iD.Connection = function() {
projection.invert([x + ts, y + ts])];
}
- return tiles
+ var q = queue(2);
+
+ var bboxes = tiles
.filter(tileAlreadyLoaded)
.map(apiExtentBox)
- .map(apiRequestExtent);
+ .forEach(function(e) {
+ q.defer(bboxFromAPI, e);
+ });
+
+ q.awaitAll(function(err, res) {
+ var g = iD.Graph();
+ res.forEach(function(r) { g = g.merge(r); });
+ event.load(err, g);
+ });
}
connection.url = function(_) {
diff --git a/js/lib/queue.js b/js/lib/queue.js
new file mode 100644
index 000000000..9a3b9da47
--- /dev/null
+++ b/js/lib/queue.js
@@ -0,0 +1,84 @@
+(function() {
+ if (typeof module === "undefined") self.queue = queue;
+ else module.exports = queue;
+
+ queue.version = "1.0.0";
+
+ function queue(parallelism) {
+ var queue = {},
+ active = 0, // number of in-flight deferrals
+ remaining = 0, // number of deferrals remaining
+ head, tail, // singly-linked list of deferrals
+ error = null,
+ results = [],
+ await = noop,
+ awaitAll;
+
+ if (arguments.length < 1) parallelism = Infinity;
+
+ queue.defer = function() {
+ if (!error) {
+ var node = arguments;
+ node.index = results.push(undefined) - 1;
+ if (tail) tail.next = node, tail = tail.next;
+ else head = tail = node;
+ ++remaining;
+ pop();
+ }
+ return queue;
+ };
+
+ queue.await = function(f) {
+ await = f;
+ awaitAll = false;
+ if (!remaining) notify();
+ return queue;
+ };
+
+ queue.awaitAll = function(f) {
+ await = f;
+ awaitAll = true;
+ if (!remaining) notify();
+ return queue;
+ };
+
+ function pop() {
+ if (head && active < parallelism) {
+ var node = head,
+ f = node[0],
+ a = Array.prototype.slice.call(node, 1),
+ i = node.index;
+ if (head === tail) head = tail = null;
+ else head = head.next;
+ ++active;
+ a.push(function(e, r) {
+ --active;
+ if (error != null) return;
+ if (e != null) {
+ // clearing remaining cancels subsequent callbacks
+ // clearing head stops queued tasks from being executed
+ // setting error ignores subsequent calls to defer
+ error = e;
+ remaining = results = head = tail = null;
+ notify();
+ } else {
+ results[i] = r;
+ if (--remaining) pop();
+ else notify();
+ }
+ });
+ f.apply(null, a);
+ }
+ }
+
+ function notify() {
+ if (error != null) await(error);
+ else if (awaitAll) await(null, results);
+ else await.apply(null, [null].concat(results));
+ }
+
+ return queue;
+ }
+
+ function noop() {}
+})();