оператор + менее эффективен, чем StringBuffer.append ()

91

В моей команде мы обычно выполняем конкатенацию строк следующим образом:

var url = // some dynamically generated URL
var sb = new StringBuffer();
sb.append("<a href='").append(url).append("'>click here</a>");

Очевидно, что гораздо удобнее читать следующее:

var url = // some dynamically generated URL
var sb = "<a href='" + url + "'>click here</a>";

Но эксперты JS утверждают, что +оператор менее производительный, чем StringBuffer.append(). Это правда?

Dónal
источник
93
В javascript нет StringBuffer
Томас
7
Дон, ты имел в виду Java?
Джеймс МакМахон
Мой опыт [].join('')показал, что это показало действительно запрограммированное поведение, так что я вернулся к +: - /
martyglaubitz
1
Я знаю, что основной вопрос здесь касается конкатенации строк, но вы должны проявлять осторожность при создании таких html-элементов. Ваш пример может сломаться, если urlсодержит 'или \n.
Styfle
Возможный дубликат наиболее эффективного способа объединения строк в JavaScript?
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Ответы:

46

Internet Explorer - единственный браузер, который действительно страдает от этого в современном мире. (Версии 5, 6 и 7 были очень медленными. 8 не демонстрирует такой же деградации.) Более того, IE становится все медленнее и медленнее, чем длиннее ваша строка.

Если вам нужно объединить длинные строки, обязательно используйте технику array.join. (Или какую-нибудь оболочку StringBuffer для удобства чтения.) Но если ваши строки короткие, не беспокойтесь.

пкоркоран
источник
102

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

Вот подробный анализ производительности, который показывает производительность с использованием всех различных методов конкатенации JavaScript во многих разных браузерах; Производительность строки и анализ

join () один раз, concat () один раз, join () для, + = для, concat () для

Подробнее:
Ajaxian >> Производительность строк в IE: Array.join vs + = продолжение

Эрик Шуновер
источник
9
Что касается графика, если он не очевиден; ниже - лучше.
Teekin
1
«Перво-наперво с улучшением производительности в IE7, нам больше не нужно рассматривать использование альтернативного пути при выполнении крупномасштабных строковых операций; использование Array.join в итеративной ситуации не дает вам серьезных преимуществ, чем использование + = в той же ситуации. Кроме того, отличия от IE6 были достаточно небольшими, чтобы вы не беспокоились о разветвлении для этой конкретной версии ».
Chris S
2
@ Крис, это неправда. Сравните эти две скрипки в IE7 : jsfiddle.net/9uS4n/5 (быстро) и jsfiddle.net/9uS4n/2 (медленно). Похоже, что при использовании этой join()техники производительность улучшается как минимум в 1000 раз .
Кирк Уолл
Хорошее объяснение. Пожалуйста, также просмотрите это: iliadraznin.com/2012/03/…
will824
37

Да, это правда, но тебе все равно. Выбирайте тот, который легче читать. Если вам нужно протестировать приложение, сосредоточьтесь на узких местах.

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

Майкл Харен
источник
31

Согласен с Майклом Хареном .

Также рассмотрите возможность использования массивов и присоединения, если производительность действительно является проблемой.

var buffer = ["<a href='", url, "'>click here</a>"];
buffer.push("More stuff");
alert(buffer.join(""));
Франк Крюгер
источник
3
Я знаю, что выбран правильный ответ, но в этом ответе есть более полезный пример.
Джейсон Сперске
1
Вау просто вау. Сравните эти две скрипки в IE7 : jsfiddle.net/9uS4n/5 (быстро) и jsfiddle.net/9uS4n/2 (медленно). Похоже, что при использовании этой техники производительность улучшается как минимум в 1000 раз.
Кирк Уолл
@KirkWoll: Возможно, в будущем захочется использовать jsPerf, чтобы мы могли легко сравнивать результаты.
rvighne
Я тоже делал это в последнее время, стиль кода похож на .NET StringBuilder, var sb = []; sb.push («раздел 1»); sb.push («раздел 2»); вернуть sb.join ('');
Сэм Джонс
Этот jsPerf jsperf.com/join-concat/2, упомянутый по адресу: stackoverflow.com/questions/16696632/…, похоже, указывает, что +=это быстрее.
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
18

Попробуй это:

var s = ["<a href='", url, "'>click here</a>"].join("");
Рахул
источник
Что ж, сообщение, на которое вы ссылаетесь в своем ответе, специально пытается опровергнуть «миф» о Array.join, о котором говорит мой ответ. Так что, возможно, нет. Я просто опубликовал то, что видел быстрее на практике.
Рахул
люблю этот метод конкатенации строк.
bkwdesign
8

Как уже отметили некоторые пользователи: это не имеет отношения к маленьким строкам.

А новые движки JavaScript в Firefox, Safari или Google Chrome оптимизируют так

"<a href='" + url + "'>click here</a>";

так же быстро, как

["<a href='", url, "'>click here</a>"].join("");
смесь
источник
8

JavaScript не имеет собственного объекта StringBuffer, поэтому я предполагаю, что это из библиотеки, которую вы используете, или особенности необычной среды хоста (то есть не браузера).

Я сомневаюсь, что библиотека (написанная на JS) могла бы производить что-либо быстрее, хотя собственный объект StringBuffer мог бы. Окончательный ответ можно найти с помощью профилировщика (если вы работаете в браузере, Firebug предоставит вам профилировщик для движка JS, найденного в Firefox).

Квентин
источник
6

По словам Кнута, «преждевременная оптимизация - корень всех зол!» Небольшое отклонение в любом случае, скорее всего, не будет иметь большого эффекта в конце; Я бы выбрал более читаемый.

Уильям Келлер
источник
1
Традиционно StringBuffer используется вместо конкатенации, потому что первый имеет временную сложность O (N), тогда как второй - O (N ^ 2), поэтому разница значительна для больших N (но не для малых N). В любом случае сценарий O (N ^ 2) может не выполняться в JavaScript в зависимости от используемой среды.
redcalx
4

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

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

Эд Керн
источник
3

Довольно легко настроить быстрый тест и проверить вариации производительности Javascript с помощью jspref.com. . Которого, вероятно, не было, когда задавали этот вопрос. Но тем, кто сталкивается с этим вопросом, стоит взглянуть на сайт.

Я быстро протестировал различные методы конкатенации на http://jsperf.com/string-concat-methods-test .

Джеймс МакМахон
источник
Судя по этому, в настоящее время похоже, что конкатенация с оператором + определенно лучший способ. Если только я не читаю неправильно. Что вполне вероятно.
Ричард
2

Мне нравится использовать функциональный стиль, например:

function href(url,txt) {
  return "<a href='" +url+ "'>" +txt+ "</a>"
}

function li(txt) {
  return "<li>" +txt+ "</li>"
}

function ul(arr) {
  return "<ul>" + arr.map(li).join("") + "</ul>"
}

document.write(
  ul(
    [
      href("http://url1","link1"),
      href("http://url2","link2"),
      href("http://url3","link3")
    ]
  )
)

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

Это также имеет тенденцию автоматически использовать промежуточные строки.

jasonc65
источник
1

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

Дэвид Амеллер
источник
На самом деле это неплохой совет, я не знаю, почему он так сильно отклонен. Я знаю, что он не отвечает на конкретный вопрос, но он заслуживает признания как в целом хороший совет.
век
0

Да, по обычным тестам. Например: http://mckoss.com/jscript/SpeedTrial.htm .

Но для маленьких струн это не имеет значения. Вы будете заботиться только об исполнении на очень больших струнах. Более того, в большинстве JS-скриптов узкое место редко связано с манипуляциями со строками, поскольку их недостаточно.

Вам лучше понаблюдать за манипуляциями с DOM.

e-satis
источник
Ссылка мертва .. https://web.archive.org/web/20150912072015/http://mckoss.com/jscript/SpeedTrial.htm указывает на версию веб-архива.
Тони