2009-03-23 2 views
50

У меня есть JavaScript, который выполняет множество вычислений, а также чтение/запись значений из/в DOM. Страница огромна, так что это часто заканчивается блокировкой браузера в течение минуты (иногда дольше с IE) со 100% использованием ЦП.Предотвращение длительного запуска javascript от блокировки браузера

Есть ли какие-нибудь ресурсы для оптимизации JavaScript, чтобы это не происходило (все, что я могу найти, это как отключить предупреждение о запуске Firefox Firefox)?

ответ

44

Если вы можете превратить свой алгоритм вычисления в то, что можно назвать итеративно, вы можете временно отменить управление браузером через 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 (pump, 0)'? Или это, возможно, сохранило бы предварительный код браузера, который реагирует на ввод мыши, обновляет метр прогресса или другие элементы DOM? – Andy

+0

@ Andy Да 'setTimeout' с 0 тоже поможет. См. Некоторые ответы на [этот вопрос] (https://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful). – ShreevatsaR

1

Вы можете попробовать выполнить долговременные вычисления в потоках (см. JavaScript and Threads), хотя они не очень переносимы.

Вы также можете попробовать использовать профайлер Javascript, чтобы найти узкие места производительности. Firebug поддерживает профилирование javascript.

7

Использовать таймауты.

Помещая содержимое вашего цикла (ов) в отдельные функции и вызывая их из setTimeout() с тайм-аутом 50 или около того, javascript даст управление потоком и вернется через некоторое время, что позволит UI, чтобы получить внешний вид.

Удачная проработка here.

2

я писал о in-browser performance некоторое время назад, но позвольте мне суммировать те, связанные с DOM для вас здесь.

  • Обновите DOM как можно реже. Внесите свои изменения в объекты DOM в памяти и добавьте их только один раз в DOM.
  • Использование innerHTML. Это быстрее, чем методы DOM в большинстве браузеров.
  • Используйте делегацию событий вместо обычной обработки событий.
  • Знайте, какие звонки стоят дорого и избегайте их. Например, в jQuery значение $ ("div.className") будет дороже, чем $ ("# someId").

Тогда есть некоторые связанные с самим JavaScript:

  • Loop как можно меньше. Если у вас есть одна функция, которая собирает узлы DOM, а другая - обрабатывает их, вы выполняете цикл дважды. Вместо этого передайте анонимную функцию функции, которая собирает узлы и обрабатывает узлы по мере их сбора.
  • Используйте встроенную функциональность, когда это возможно. Например, для всех итераторов.
  • Используйте setTimeout, чтобы позволить браузеру дышать раз в то время.
  • Для дорогостоящих функций, которые имеют идемпотентные выходы, кешируйте результаты, чтобы вам не приходилось перепрограммировать их.

В моем блоге есть еще одна ссылка (ссылка выше).

1

Это все еще немного кровоточит, но Firefox 3.5 имеет такие вещи, которые называются веб-рабочими, но я не уверен в их поддержке в других браузерах.

Г-н Resig есть статья о них здесь: http://ejohn.org/blog/web-workers/

И Simulated Annealing, вероятно, самый простой пример этого, если вы обратите внимание на спиннинг Firefox логотип не замерзают, когда рабочие потоки делают их запросы (таким образом, не замораживая браузер).

+0

Почему веб-работники не ответ здесь? –

+0

Ну, я ответил на это в 09 ', так что, возможно, это было не так широко распространено тогда ... – leeand00

+0

Хороший вопрос, ну это, безусловно, должно быть наверху сейчас. Использование setTimeout звучит для меня неловко, независимо от того, что вы делаете, если вам действительно не нужен тайм-аут для чего-то. Если вы сейчас перейдете на codepen.io в Chrome Windows и выполните алгоритм с сложностью O (N!), Такой как поиск всех перестановок строки «ABCDEFGHIJKLMNOP», ваш браузер закроется и перестанет отвечать на запросы. В рабочем потоке пользовательский интерфейс продолжает работать сам по себе. Это, безусловно, правильный ответ. –

1

Мое впечатление, что манипуляция DOM, особенно в IE, является гораздо более важной проблемой для производительности, чем «основной» JavaScript (цикл и т. Д.).

Если вы строите узлы, в IE это делается намного быстрее, создавая строку HTML, а затем устанавливая innerHTML в контейнере, чем с помощью методов DOM, таких как createElement/appendChild.

0

Вы могли бы попытаться сократить код на

$(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) 
} 

У меня была такая же проблема, и мои клиенты были сообщать об этом как ошибка «Убей страницы». Но теперь я получил лучшее решение для этого. :)

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