- PVSM.RU - https://www.pvsm.ru -
Бывают задачи, когда необходимо в цикле выполнять большое количество итераций и при каждой такой итерации нужно создать объект или элемент на странице, задать css-стиль и т.д. Когда итераций немного, то проблема не существенная, а что если вам нужно создать сто, тысячу, миллион объектов?
// Антишаблон, не использовать!
for (var i = 0; i < 1000000; i ++) {
console.log(i);
}
В данном случае браузер просто перестанет реагировать и повиснет.
// Антишаблон, не использовать!
var count = 1000000;
while (count -= 1) {
console.log(count);
}
Даже если нам заранее известно количество итераций в цикле и если мы запустим цикл с последнего элемента и пойдем в порядке убывания, — как показано в примере выше — то браузер достигнув цикла, заставит пользователя ждать(в лучшем случае). И хорошо, если script расположен перед закрывающим тегом body, а не в head. В противном случае javascript не даст загрузиться html документу, пока полностью не будет выполнен.
var count = 1000000,
parts = 500, // разбиваем на 500 частей, то есть в каждой части у нас будет 2000 итераций(1000000 / 500 = 2000)
maxIterations = count / parts, // собственно итерации для каждой части
iteration = 0; // счетчик итераций
setTimeout(function createCycle() {
/*
Для разнообразия привел цикл for, но как писал уже выше, разницы между while и for по производительности нет;
так же цикл сделал по возрастанию, чтоб показать, что даже в таком случае производительность НАМНОГО больше,
чем в предыдущем примере
*/
for (var i = 0; i < maxIterations; i += 1) {
console.log(i);
}
iteration ++;
if (iteration < parts) {
/*
Так как число не маленькое(1000000), то таймер необходимо запускать с большим интервалом,
в противном случае он не успев обработать одну часть(parts) до конца(от 1 до 2000)
приступит к выполнению следующей
*/
setTimeout(createCycle, 1000);
}
}, 1000);
Если же вы разбили свой цикл на достаточно большое количество частей и в каждой части у вас вышло итераций немного, то смело ставьте интервал в 25мс(использование задержки менее 25мс в Internet Explorer может привести к блокированию браузера).
Хочу заметить, что скрипт работает асинхронно, то есть пока выполняется цикл, пользователю не нужно ждать окончания последней итерации.
Бывает, когда функция выполняется достаточно долгое время, в таком случае эту функцию желательно разделить на несколько маленьких функций, которые будут выполняться последовательно. Все, что для этого необходимо — это добавить каждую функцию в массив.
function foo1() { console.log('foo1'); }
function foo2() { console.log('foo2'); }
function foo3() { console.log('foo3'); }
function createTasks() {
var tasks = [foo1, foo2, foo3];
setTimeout(function getTask() {
tasks.shift()(); // вырезаем из массива первую функцию и обрабатываем ее, после чего берем следующую и т.д.
if (tasks.length > 0) {
setTimeout(getTask, 25);
}
}, 25);
}
createTasks();
Во всех вышеописанных примерах таймеры срабатывали последовательно друг за другом, в связи с этим влияние на производительность было минимальным. Но, как только на странице начинают срабатывать несколько таймеров одновременно — начинаются проблемы. Из-за однопоточной работы браузеров, таймеры начинают конкурировать друг с другом за время, необходимое для выполнения переданных им функций. Чтобы обойти эту проблему желательно создать единственный таймер многократного срабатывания, выполняющий множество операций при каждом срабатывании.
Автор: theNobody
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/47050
Ссылки в тексте:
[1] Источник: http://habrahabr.ru/post/200138/
Нажмите здесь для печати.