Я заметил на днях вопрос (Уменьшение использования процессора Javascript), и я был заинтригован.
По сути, парень хотел зашифровать некоторые файлы по характеру. Очевидно, что все это за один раз закроет браузер.
Его первая идея заключалась в том, чтобы сделать это в кусках примерно по 1 килобайту строки за раз, а затем сделать паузу для X ms, чтобы она позволяла пользователю продолжать взаимодействовать со страницей между обработкой. Он также рассмотрел использование webWorkers (лучшая идея), но, очевидно, это не перекрестный браузер.
Теперь я действительно не хочу вдаваться в то, почему это, вероятно, не очень хорошая идея в javascript. Но я хотел посмотреть, могу ли я придумать решение.
Я вспомнил, как смотрел видео Douglas Crockford в js conf. Видео было связано с node.js и циклом событий. Но я вспомнил, что он говорил о том, чтобы разбить длинные функции вниз на отдельные куски, поэтому вновь вызываемая функция переходит в конец цикла событий. Вместо того, чтобы забивать цикл событий с помощью длительной задачи, предотвращая что-либо еще.
Я знал, что это решение, достойное моего расследования. Будучи разработчиком интерфейсов, я никогда не сталкивался с очень большими задачами в JS и очень хотел узнать, как их разбить и как они работают.
Я решил попробовать рекурсивную функцию, которая вызывает себя внутри setTimeout 0ms. Я понял, что это обеспечит перерывы в цикле событий для чего-то еще, что должно было произойти во время его запуска. Но я также подумал, что пока ничего не происходит, вы получите максимальный расчет.
Вот что я придумал.
(Я собираюсь извиниться за код. Я экспериментировал в консоли, так что это было быстро и грязно.)
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' ) });
};
Он работал все время, когда я писал этот пост, и все еще готов к этому. Браузер не жалуется и не висит. Я добавлю время завершения, как только оно закончится.