Предотвращение блокировки браузера с помощью javascript
У меня есть JavaScript, который выполняет множество вычислений, а также чтение/запись значений из/в DOM. Страница огромна, так что это часто заканчивается блокировкой браузера в течение минуты (иногда дольше с IE) при 100% использовании ЦП.
Есть ли какие-нибудь ресурсы для оптимизации JavaScript, чтобы это не происходило (все, что я могу найти, это как отключить предупреждение Firefox script)?
Ответы
Ответ 1
если вы можете превратить свой вычислительный алгоритм во что-то, что можно назвать итеративно, вы могли бы отменить управление браузером через частые промежутки времени, используя setTimeout с коротким значением таймаута.
Например, что-то вроде этого...
function doCalculation()
{
//do your thing for a short time
//figure out how complete you are
var percent_complete=....
return percent_complete;
}
function pump()
{
var percent_complete=doCalculation();
//maybe update a progress meter here!
//carry on pumping?
if (percent_complete<100)
{
setTimeout(pump, 50);
}
}
//start the calculation
pump();
Ответ 2
Использовать таймауты.
Поместив содержимое вашего цикла (ов) в отдельные функции и вызывая их из setTimeout() с тайм-аутом 50 или около того, javascript даст управление потоком и вернется через некоторое время, разрешив интерфейс пользователя чтобы получить внешний вид.
Там будет хорошая проработка здесь.
Ответ 3
Я когда-то писал о производительности в браузере, но позвольте мне кратко изложить те, которые связаны с DOM для вас здесь.
- Обновляйте DOM как можно реже. Внесите свои изменения в объекты DOM в памяти и добавьте их только один раз в DOM.
- Используйте innerHTML. Это быстрее, чем методы DOM в большинстве браузеров.
- Используйте делегирование событий вместо обычной обработки событий.
- Знайте, какие вызовы дороги, и избегайте их. Например, в jQuery значение $( "div.className" ) будет дороже $( "# someId" ).
Затем некоторые из них связаны с самим JavaScript:
- Петля как можно меньше. Если у вас есть одна функция, которая собирает узлы DOM, а другая - обрабатывает их, вы выполняете цикл дважды. Вместо этого передайте анонимную функцию функции, которая собирает узлы и обрабатывает узлы по мере их сбора.
- При необходимости используйте встроенную функциональность. Например, для всех итераторов.
- Используйте setTimeout, чтобы позволить браузеру дышать раз в то время.
- Для дорогостоящих функций, имеющих идемпотентные выходы, кешируйте результаты, чтобы вам не приходилось его компрометировать.
Там еще несколько в моем блоге (ссылка выше).
Ответ 4
Это все еще немного кровоточит, но Firefox 3.5 имеет такие вещи, которые называются веб-рабочими, но я не уверен в их поддержке в других браузерах.
г. У Resig есть статья о них здесь: http://ejohn.org/blog/web-workers/
И Simulated Annealing, вероятно, самый простой пример, если вы заметите, что вращающийся логотип Firefox не замерзает, когда рабочие потоки выполняют свои запросы (таким образом, не замораживая браузер).
Ответ 5
Вы можете попробовать выполнить долговременные вычисления в потоках (см. JavaScript и темы), хотя они не очень переносимы.
Вы также можете попробовать использовать какой-либо Javascript-профайлер, чтобы найти узкие места производительности. Firebug поддерживает профилирование javascript.
Ответ 6
Мой опыт заключается в том, что манипуляции с DOM, особенно в IE, гораздо более важны для производительности, чем "основной" JavaScript (цикл и т.д.).
Если вы создаете узлы, в IE это намного быстрее, создавая строку HTML, а затем устанавливая innerHTML в контейнере, чем с помощью методов DOM, таких как createElement/appendChild.
Ответ 7
Вы можете попытаться сократить код
$(xmlDoc).find("Object").each(function(arg1) {
(function(arg1_received) {
setTimeout(function(arg1_received_reached) {
//your stuff with the arg1_received_reached goes here
}(arg1_received), 0)
})(arg1)
}(this));
или для циклов "для" попробуйте
for (var i = 0 ; i < 10000 ; i = i + 1) {
(function(arg1_received) {
setTimeout(function(arg1_received_reached) {
//your stuff with the arg1_received_reached goes here
}(arg1_received), 0)
})(arg1_to_send)
}
У меня была такая же проблема, и мои клиенты сообщали об этом как об ошибке "Убить страницу". Но теперь я получил лучшее решение для этого.:)