Я заметил здесь вопрос на днях ( Сокращение загрузки процессора Javascript ), и я был заинтригован.
По сути, парень хотел зашифровать некоторые файлы символ за символом.Очевидно, что все это за один раз заблокирует браузер.
Его первая идея состояла в том, чтобы делать это порциями по 1 килобайту за раз, затем делать паузу в X мс, чтобы позволить пользователю продолжать взаимодействовать со страницей между обработками.Он также подумал об использовании webWorkers (лучшая идея), но, очевидно, это не кросс-браузер.
Теперь я не хочу вдаваться в подробности, почему это, вероятно, не очень хорошая идея в javascript.Но я хотел посмотреть, смогу ли я найти решение.
Я вспомнил, как смотрел видео Дугласа Крокфорда на конференции js conf .Видео было связано с node.js и циклом событий.Но я вспомнил, как он говорил о разбиении долго выполняющихся функций на отдельные фрагменты, поэтому вновь вызываемая функция переходит в конец цикла событий.Вместо того, чтобы засорять цикл событий долго выполняемой задачей, предотвращая что-либо еще.
Я знал, что это решение заслуживает моего расследования.Как передовой разработчик, я никогда не сталкивался с чрезвычайно долго выполняемыми задачами в JS, и мне было интересно узнать, как их разбить и как они выполняются.
Я решил попробовать рекурсивную функцию, котораявызывает себя изнутри setTimeout 0 мс.Я полагал, что это обеспечит разрывы в цикле событий для всего, что хочет случиться во время его работы.Но я также подумал, что, хотя больше ничего не происходит, вы получите максимум вычислений.
Вот что я придумал.
(Я собираюсь извиниться за код. Я экспериментировал в консоли, так что это было быстро и грязно.)
function test(i, ar, callback, start){
if ( ar === undefined ){
var ar = [],
start = new Date;
};
if ( ar.length < i ){
ar.push( i - ( i - ar.length ) );
setTimeout(function(){
test( i, ar, callback, start);
},0);
}
else {
callback(ar, start);
};
}
(Вы можете вставить этот код в консоль, и он будет работать)
По сути, то, что делает функция, - это получение числа, создание массива и вызов себя, в то время как array.length < number
пока подталкивает счет.в массив.Он передает массив, созданный при первом вызове, всем последующим вызовам.
Я проверил его, и он, кажется, работает точно так, как задумано.Только его производительность довольно плохая.Я проверил это с помощью ..
(опять же, это не сексуальный код)
test(5000, undefined, function(ar, start ){
var finish = new Date;
console.log(
ar.length,
'timeTaken: ', finish - start
);
});
Теперь я, очевидно, хотел знать, сколько времени это заняло, приведенный выше код занял около 20 секунд.Теперь мне кажется, что для JS не нужно 20 секунд, чтобы сосчитать до 5000. Добавьте к этому тот факт, что он выполняет некоторые вычисления и обработку для помещения элементов в массив.Но все же 20-е годы немного крутые.
Поэтому я решил создать несколько одновременно, чтобы увидеть, как это повлияло на производительность браузера и скорость вычислений.
(код не становится более сексуальным)
function foo(){
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 1' ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 2' ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 3' ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 4' ) });
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 5' ) });
};
Таким образом, всего пять, запущенных одновременно и не вызывающих зависания браузера.
после завершения процесса все результаты возвращаются практически в одно и то же время.для их завершения потребовалось около 21,5 с.Это всего лишь на 1,5 секунды медленнее, чем один сам по себе.Но я перемещал мышь по окну на элементах, которые имели :hover
эффекты, просто чтобы убедиться, что браузер все еще реагирует, так что это может объяснить некоторые издержки 1,5 с.
Так как эти функцииочевидно, работают параллельно, в браузере осталось больше вычислительного сока.
Кто-нибудь может объяснить, что здесь происходит с точки зрения производительности, и дать подробные сведения о том, как улучшить такие функции?
Просто чтобы сойти с ума, я сделал это ..
function foo(){
var count = 100000000000000000000000000000000000000;
test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 1' ) });
test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 2' ) });
test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 3' ) });
test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 4' ) });
test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 5' ) });
};
Он работал все время, пока я писал этот пост, и все еще продолжаю его.Браузер не жалуется или зависает.Я добавлю время завершения, как только оно закончится.