2009-06-05 2 views
4

У меня есть большой набор данных, которые будут отображаться на карте Google. Из-за размера набора данных карта google всегда зависает в течение нескольких секунд, прежде чем все точки будут построены. Во время загрузки я использовал анимационный вращающийся круг, чтобы показать, что он находится в процессе. Но конечные пользователи предпочитают видеть действия. Они хотят, чтобы данные, построенные на карте, шаг за шагом, а не все в один раз. Поскольку javascript не поддерживает многопоточность, как лучше всего подойти к этому?Пользовательский интерфейс и javascript

+0

Я не испортил Карты Google. Насколько это находится под вашим контролем и насколько он находится в Google? – Nosredna

ответ

7

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.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 «пятна» в документ). Чтобы увидеть разницу, установить размер пакета, равный числу точек:

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 ? '; ' : ''); 
}); 
+0

Мне нравится это решение. это просто и интуитивно понятно. – airportyh

4

Не могли бы вы построить их в партиях, с небольшой задержкой (setTimeout) между каждой?

4

Javascript может не поддерживать несколько потоков нормально, но вы можете добиться эффекта.

function spawnThread(func, params){ 
    window.setTimeout(
     (function(f, p){ 
     return function(){ 
      f.call(p); 
     } 
    )(func, params), 0 
    ) 
} 

Основная проблема с этим методом было бы, конечно, проверка на успех нити, я предполагаю, что вы могли бы справиться с этим с помощью глобальной переменной или что-то подобное, не было бы отличным решением, но это сработает.

+2

Настройка таймаута не создает никаких новых потоков (JavaScript работает в abrowser в одном потоке всегда). Вместо этого, используя эту технику, вы делите длинную задачу на меньшую и отложите ее выполнение до того, как предыдущий будет выполнен, и браузер сделает краткий. –

+0

setTimeout на самом деле не порождает темы. setTimeout отменяет выполнение до тех пор, пока не будет достигнуто заданное количество миллисекунд. –

1

Подобно тому, что musicfreak сказал, но не требует Gears, является Javascript web workers. В настоящее время это реализовано только в последних версиях браузеров.

Смежные вопросы