Подтвердить что ты не робот

Конкатенация строк по строковым буферам в Javascript

Я читал эту книгу. Профессиональный Javascript для веб-разработчиков, где автор упоминает, что конкатенация строк - это дорогостоящая операция по сравнению с использованием массива для хранения строк, а затем с помощью метода join для создания окончательной строки. Любопытный, я сделал пару тестов здесь, чтобы узнать, сколько времени он спасет, и это то, что я получил -

http://jsbin.com/ivako

Как-то, Firefox обычно производит несколько схожие времена в обоих направлениях, но в IE конкатенация строк намного быстрее. Итак, может ли эта идея теперь считаться устаревшей (браузеры, вероятно, улучшились с тех пор?

4b9b3361

Ответ 1

** EDIT: Я предполагаю, что люди все еще рассматривают этот пост, но прошло 3 года, поэтому вам лучше всего посмотреть: http://jsperf.com/string-concatenation/14

Просмотрите изменения этого сообщения, чтобы узнать, что он говорил.

Ответ 2

Даже если это было верно, и join() был быстрее, чем конкатенация, это не имело бы значения. Мы говорим о крошечных количествах милисекунд здесь, которые совершенно ничтожны.

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

Только мои два цента.

Ответ 3

В моей системе (IE 8 в Windows 7) время StringBuilder в этом тесте очень примерно 70-100% в диапазоне, то есть оно нестабильно, хотя среднее значение составляет около 95% от значения нормальное добавление.

Хотя теперь легко сказать "преждевременная оптимизация" (и я подозреваю, что почти в каждом случае это есть) есть вещи, которые стоит рассмотреть:

Проблема с повторным конкатенацией строк происходит с повторными выделениями памяти и повторными копиями данных (расширенные типы данных строк могут уменьшить/устранить большую часть этого, но теперь пусть предполагается упрощенная модель). Из этого можно задать несколько вопросов:

  • Какое распределение памяти используется? В наивном случае каждая str + = x требует выделения длины str.length + x.length. Например, стандартный C malloc является довольно плохим распределителем памяти. Реализации JS претерпели изменения на протяжении многих лет, включая, среди прочего, улучшенные подсистемы памяти. Конечно, эти изменения не останавливаются на достигнутом и затрагивают все аспекты современного JS-кода. Потому что теперь древние реализации, возможно, были невероятно медленными в определенных задачах, не обязательно подразумевают, что одни и те же проблемы все еще существуют или в одинаковых экстентах.

  • Как и выше, реализация Array.join очень важна. Если он не предварительно выделяет память для окончательной строки перед ее созданием, тогда она экономит только затраты на копирование данных - сколько ГБ/с является основной памятью в наши дни? 10 000 x 50 вряд ли нажимают лимит. Ожидается, что умная операция Array.join с АССОЦИАЦИЯМИ ПЛОХОЙ ПАМЯТИ будет выполнять бит лучше, потому что количество перераспределений уменьшается. Это различие, как ожидается, будет сведено к минимуму, поскольку стоимость распределения уменьшается.

  • Ключ для микро-тестов может быть ошибочным в зависимости от того, создает ли JS-движок новый объект для каждого строкового литерала UNIQUE или нет. (Это будет смещать его к методу Array.join, но его необходимо рассматривать в целом).

  • Тест - это, по сути, микро-тест:) Увеличение растущего размера должно влиять на производительность, основанную на любых или всех (а затем и некоторых) выше условиях. Как правило, легко показать крайние случаи, способствующие тому или иному методу - ожидаемый прецедент обычно имеет большее значение.

Хотя, честно говоря, для любой формы строкового построения строк я бы просто использовал обычную конкатенацию строк, пока такое время не было определено как узкое место, если когда-либо.

Я бы перечитал вышеприведенное утверждение из книги и посмотрел, есть ли, возможно, другие неявные соображения, которые автор действительно имел в виду, например, "для очень больших строк" ​​или "безумные количества операций с строками" или "в JScript/IE6" и т.д. Если нет, то такой оператор примерно так же полезен, как "Insert sort is O (n * n)" [реализованные затраты зависят от состояния данных и размера n, конечно).

И отказ от ответственности: скорость кода зависит от браузера, операционной системы, основного оборудования, гравитационных сил Луны и, конечно, от того, как ваш компьютер чувствует к вам.

Ответ 4

В принципе книга правильная. Присоединение массива должно быть намного быстрее, чем повторное объединение одной и той же строки. Как простой алгоритм на неизменяемых строках он явно быстрее.

Фокус в том, что авторы JavaScript, будучи в значительной степени неспецифическими dabblers, написали загрузку кода в дикой природе, которая использует конкатенацию, и относительно немного "хорошего кода", использующего такие методы, как array-join. Результатом является то, что авторы браузера могут получить лучшее улучшение скорости на средней веб-странице, поддерживая и оптимизируя "плохой, более общий вариант конкатенации".

Итак, что случилось. В более новых версиях браузера есть довольно волосатая оптимизация, которая обнаруживает, когда вы выполняете загрузку конкатенаций, и взламывает ее так, чтобы она внутренне работала больше, чем объединение массива, с большей или меньшей скоростью.

Ответ 5

На самом деле у меня есть некоторый опыт в этой области, так как мой основной продукт - это большой IE-only webapp, который делает LOT конкатенации строк, чтобы создать XML-документы для отправки на сервер. Например, в худшем случае страница может иметь 5-10 фреймов, каждая из которых содержит несколько сотен текстовых полей, каждая из которых имеет 5-10 свойств expando.

Для чего-то вроде нашей функции сохранения, мы перебираем каждую вкладку (iframe) и каждый объект на этой вкладке, вытаскиваем все свойства expando для каждого объекта и добавляем их все в гигантский XML-документ.

При профилировании и улучшении нашего метода сохранения мы обнаружили, что использование конкатенации строк в IE7 было намного медленнее, чем использование метода массивов строк. Некоторые другие интересные моменты заключались в том, что доступ к свойствам объекта expand DOM очень медленный, поэтому мы помещаем их все в массивы javascript. Наконец, генерация самих массивов javascript на самом деле лучше всего выполняется на сервере, а затем вы записываете на страницу как литеральный элемент управления, который будет вызываться при загрузке страницы.

Ответ 6

Как известно, не все браузеры созданы равными. Из-за этого производительность в разных областях гарантированно будет отличаться от браузера к браузеру.

В стороне, я заметил те же результаты, что и вы; однако после удаления ненужного класса буфера и просто с использованием массива напрямую и строки 10000 символов результаты были еще более жесткими/согласованными (в FF 3.0.12): http://jsbin.com/ehalu/

Если вы не выполняете много конкатенации строк, я бы сказал, что этот тип оптимизации - это микро-оптимизация. Ваше время может быть лучше потрачено на ограничение DOM reflows и query (как правило, использование document.getElementbyById/getElementByTagName), реализующее кэширование результатов AJAX (где это применимо) и использование пузырьков событий (там где-то есть ссылка, я просто не могу ее найти сейчас).

Ответ 7

Хорошо, это касается связанного модуля:

http://www.openjsan.org/doc/s/sh/shogo4405/String/Buffer/0.0.1/lib/String/Buffer.html

Это эффективное средство создания буферов String с помощью

var buffer = new String.Buffer();
buffer.append("foo", "bar");

Это самая быстрая реализация буферов String, о которых я знаю. Прежде всего, если вы используете String Buffers, не используйте push, потому что это встроенный метод, и он медленный, поскольку один push итерации выполняется по всему массиву аргументов, а не просто добавлению одного элемента.

Все это действительно зависит от реализации метода join, некоторые реализации метода соединения очень медленны, а некоторые относительно большие.