2010-10-03 2 views
0

Я писал алгоритм JS. Он быстро вспыхивает в хроме и собаке медленно в FF. В хром-профилировщике я трачу < 10% в методе, в FF тот же метод составляет 30% от времени выполнения. Есть ли конструкции javascript, чтобы избежать, потому что они действительно медленны в одном браузере или другом?Конструкции javascript, которых нужно избегать?

Одна вещь, которую я заметил, это то, что такие вещи, как простое объявление переменной, могут быть дорогими, если вы этого достаточно. Я разогнал свой алгоритм заметному, не делая вещи, как

var x = y.x; 
dosomthing(x); 

и просто делать

dosomething(y.x) 

, например.

+0

Переменные дешевые. Назначение также дешево, поскольку оно копирует только примитивные значения или ссылки в случае объектов. Я не думаю, что это может быть узким местом производительности. – galambalazs

+0

@ galambalazs, делая что-то сотни тысяч раз, я думаю, что каждое задание имеет значение? – hvgotcodes

+0

определенно проверьте это [предложение] (http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2 «обзор кода»).Это почти так, просто нужно немного больше поддержки :) – greatwolf

ответ

5

Как вы обнаружили, разные вещи являются проблемами в разных реализациях. По моему опыту, если не делать действительно глупых вещей, не стоит беспокоиться о том, чтобы оптимизировать ваш код JavaScript до тех пор, пока вы не столкнетесь с определенной проблемой производительности при тестировании в целевых браузерах. Такие простые вещи, как обычная оптимизация «отсчет до нуля» (for (i = length - 1; i >= 0; --i) вместо for (i = 0; i < length; ++i)), даже не являются надежными в реализации. Поэтому я склонен придерживаться написания кода, который достаточно ясен (потому что я хочу быть хорошим для тех, кто должен его поддерживать, что часто бывает у меня), а затем беспокоиться о оптимизации, если и когда.

Сказанное, просматривающее the Google article, что tszming, связанный с в his/her answer, напомнил мне, что есть некоторые вещи, которые я имею в виду при написании кода изначально. Вот список (некоторые из этой статьи, некоторые нет):

  1. Когда вы создаете длинную строку из большого количества фрагментов, неожиданно вы обычно получить более высокую производительность, если вы строите массив фрагментов а затем используйте метод Array#join для создания окончательной строки. Я делаю это много, если я создаю большой фрагмент HTML, который я буду добавлять на страницу.

  2. Crockford private instance variable pattern, хотя и классный и мощный, стоит дорого. Я стараюсь избегать этого.

  3. with дорого и легко понять неправильно. Избегай это.

  4. Утечки памяти, конечно же, дороги в конечном итоге. Их легко создавать в браузерах, когда вы взаимодействуете с элементами DOM. См. Статью для более подробной информации, но в основном, подключите обработчики событий с помощью хорошей библиотеки, такой как jQuery, Prototype, Closure и т. Д. (Потому что это особенно уязвимая область и библиотеки помогают) и избегайте хранения ссылок на элементы DOM на других DOM элементов (прямо или косвенно) через свойства expando.

  5. Если вы строите значительное динамическое отображение контента в браузере, innerHTML намного быстрее, в большинстве случаев, чем при использовании методов DOM (createElement и appendChild). Это связано с тем, что эффективный анализ HTML в их внутренних структурах - , что делают браузеры, и они делают это очень быстро, используя оптимизированный, скомпилированный код, записывающий непосредственно в свои внутренние структуры данных. Напротив, если вы создаете значительное дерево с помощью методов DOM, вы используете интерпретируемый (обычно) язык, говорящий с абстракцией, которую браузер должен переводить, чтобы соответствовать ее внутренним структурам. Я сделал a few experiments некоторое время назад, и разница была примерно на порядок (в пользу innerHTML).И, конечно, если вы создаете большую строку для назначения innerHTML, см. Подсказку выше   — Лучше всего создавать фрагменты в массиве, а затем использовать join.

  6. Кэш результатов известных операций медленного действия, но не переусердствуйте и сохраняйте вещи только в том случае, если они вам понадобятся. Помните о стоимости сохранения ссылки и стоимости ее поиска.

  7. Я уже неоднократно слышал, как люди говорят, что доступ к vars из области сдерживания (конечно, глобальный выбор будет конечным примером этого, но вы можете сделать это с закрытием в других областях) медленнее, чем доступ к локальным, и, конечно же, это будет иметь смысл в чисто интерпретированной, не оптимизированной реализации из-за того, как определяется цепочка областей. Но я никогда на самом деле не видел, что это оказалось существенной разницей на практике. (Link to simple quick-and-dirty test) Фактически globals являются особыми, поскольку они являются объектами объекта window, который является объектом-хозяином и поэтому немного отличается от анонимных объектов, используемых для других уровней области. Но я ожидаю, что вы все равно избегаете глобалов.

Вот пример №6. Я действительно видел это в вопрос, связанный с Prototype несколько недель назад:

for (i = 0; i < $$('.foo').length; ++i) { 
    if ($$('.foo')[i].hasClass("bar")) { // I forget what this actually was 
     $$('.foo')[i].setStyle({/* ... */}); 
    } 
} 

В Prototype, $$ делает дорогая вещь: Она ищет через дерево DOM подберет элементов (в данном случае, элементы с классом "Foo"). Приведенный выше код выполняет поиск DOM три раза по адресу каждый цикл: сначала проверьте, находится ли индекс в границах, а затем при проверке, имеет ли элемент класс «бар», а затем при настройке стиля.

Это просто сумасшедший, и это будет безумие, независимо от того, в каком браузере он работает. Вы явно хотите кэшировать, что поиск кратко:

list = $$('.foo'); 
for (i = 0; i < list.length; ++i) { 
    if (list[i].hasClass("bar")) { // I forget what this actually was 
     list[i].setStyle({/* ... */}); 
    } 
} 

... но принимать его дальше (например, работа в обратном направлении до нуля) не имеет смысла, это может быть быстрее на одном браузере и медленнее на другой.

+1

Что касается «count down to 0», я недавно увидел еще один вариант, который, как я думал, был умным (если немного запутанным): 'for (var i = arr.length ; i--;) ' –

+0

@Ryan: :-) Да, я видел этого (и его двоюродного брата,' var i = arr.length; while (i -) ... '). –

1
+4

Пожалуйста, не делайте ссылки только на ответы: http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers –

+0

Другая причина в том, что ссылка может быть нарушена через некоторое время. –

1

Я не думаю, что это на самом деле производительность вещь, но что-то, чтобы избежать наверняка, если вы действительно не знаю, что происходит это:

var a = something.getArrayOfWhatever(); 
for (var element in a) { 
    // aaaa! no!! please don't do this!!! 
} 

Другими словами, следует избегать использования конструкции for ... in на массивах. Даже при итерации через свойства объекта это сложно.

Кроме того, моя любимая вещь, которую следует избегать, заключается в том, чтобы избежать пропуска var при объявлении локальных переменных!

+0

... или действительно глобальные переменные! – bobince

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