є оператором + менш ефективним, ніж 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(). Це справді правда?


92
У javascript немає StringBuffer
Томас

7
Дон, ти мав на увазі Java?
James McMahon

Мій досвід [].join('')показав, що дійсно проводна поведінка, тому я повернувся до +: - /
martyglaubitz

1
Я знаю, що основне питання тут стосується конкатенації рядків, але ви повинні бути обережними при створенні таких елементів HTML. Ваш приклад може зламатися, якщо urlмістить 'або \n.
styfle

Відповіді:


46

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

Якщо у вас є довгі рядки для об'єднання, тоді однозначно використовуйте техніку array.join. (Або якась обгортка StringBuffer навколо цього, для читабельності.) Але якщо ваші рядки короткі, не турбуйтеся.


102

Ваш приклад не є добрим, оскільки дуже малоймовірно, що виступ буде суттєво іншим. У вашому прикладі читабельність повинна переважати продуктивність, оскільки приріст продуктивності одного проти іншого незначний. Переваги масиву (StringBuffer) очевидні лише тоді, коли ви робите багато об'єднань. Навіть тоді ваш пробіг може дуже залежати від вашого браузера.

Ось детальний аналіз продуктивності, який показує продуктивність із використанням усіх різних методів конкатенації JavaScript у багатьох різних браузерах; Стрункове виконання аналізу

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

Більше:
Ajaxian >> Виконання рядка в IE: Array.join vs + = продовження


9
Щодо графіка, якщо це не очевидно; нижчий - краще.
Teekin

1
"Перш за все з покращення продуктивності за допомогою IE7, нам більше не потрібно розглядати можливість використання альтернативного шляху під час великомасштабних рядкових операцій; використання Array.join в ітеративній ситуації не дає вам основних переваг, ніж використання + = в тій самій ситуації. Крім того, відмінності з IE6 були досить незначними, щоб дозволити вам не турбуватися про розгалуження для цієї конкретної версії ".
Chris S

2
@Chris, це неправда. Порівняйте ці дві скрипки в IE7 : jsfiddle.net/9uS4n/5 (швидко) та jsfiddle.net/9uS4n/2 (повільно). Здається, спостерігається принаймні в 1000 разів поліпшення продуктивності за допомогою цієї join()техніки.
Kirk Woll,

Гарне пояснення. Також перегляньте це: 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 разів покращення продуктивності за допомогою цієї техніки.
Kirk Woll,

@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 / ... , здається, вказує , що +=це швидше.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

18

Спробуйте це:

var s = ["<a href='", url, "'>click here</a>"].join("");

Що ж, публікація, на яку ви посилаєтесь у своїй відповіді, спеціально намагається спростувати "міф" Array.join, який наводить моя відповідь. Тож, можливо, ні. Я просто опублікував те, що я бачив, на практиці швидше.
Рахул

люблю цей метод рядка concat.
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")
    ]
  )
)

Цей стиль виглядає читабельним і прозорим. Це призводить до створення утиліт, що зменшує повторення коду.

Це також, як правило, автоматично використовує проміжні рядки.


1

Наскільки я знаю, кожна конкатенація передбачає перерозподіл пам'яті. Отже, проблема полягає не в операторі, який використовувався для цього, рішення полягає в зменшенні кількості об’єднань. Наприклад, робіть конкатенації поза структурами ітерацій, коли можете.


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

0

Так, за звичайними орієнтирами. Наприклад: http://mckoss.com/jscript/SpeedTrial.htm .

Але для маленьких струн це не має значення. Вас турбуватимуть лише виступи на дуже великих струнах. Більше того, у більшості сценаріїв JS на горловині пляшки рідко трапляються маніпуляції зі струнами, оскільки їх недостатньо.

Вам краще спостерігати за маніпуляцією DOM.


Посилання мертве .. https://web.archive.org/web/20150912072015/http://mckoss.com/jscript/SpeedTrial.htm вказує на версію веб-архіву.
Тоні,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.