Javascript Engine выполняет функции одну за другой, отбирая их из очереди. Функции могут быть помещены туда либо вашим скриптом, либо как результат действий пользователя (обработчики событий). Поэтому идея состоит в том, чтобы разбить долгосрочную задачу на маленькие краткосрочные подзадачи и передать их в эту «очередь» таким образом, чтобы они могли быть смешаны с функциями, реагирующими на действия пользователя.
Это можно сделать, вызвав setTimeout окна с нулевой задержкой и передав вашу подзадачу как функцию. Таким образом, вы дадите возможность выполнению обработчика событий пользовательского интерфейса раньше
function plotSpot(spot) {
// adding spots to map
};
var spots = [1,2,3,4,5,6,7,8,9,10,11,12];
var plotSpotsBatch;
plotSpotsBatch = function() {
var spotsInBatch = 10;
while(spots.length > 0 && spotsInBatch--) {
var spot = spots.shift();
plotSpot(spot);
}
if (spots.length > 0) {
setTimeout(plotSpotsBatch, 0);
}
};
plotSpotsBatch();
Вот расширение для прототипа Array:
Array.prototype.forEachInBatches = function(batchSize, func) {
var arr = this;
var i = 0;
var doer;
doer = function() {
setTimeout(function() {
for (var stopBatch = i + batchSize; i < stopBatch && i < arr.length; i++) {
func(arr[i], i);
}
if (i < arr.length) {
doer();
}
}, 0);
};
doer();
};
Пример использования (где-то в документе должен быть div с id 'spot'). Чтобы увидеть разницу, установите размер партии равным количеству точек:
var spots = [];
for (var i = 0; i < 10000; i++) {
spots.push('{x: ' + Math.ceil(Math.random() * 180) + ', y: ' + Math.ceil(Math.random() * 180) + '}');
}
spots.forEachInBatches(10, function(spot, i) {
document.getElementById('spots').innerHTML += spot + (i < spots.length ? '; ' : '');
});