jest operatorem + mniej wydajnym niż StringBuffer.append ()


91

W moim zespole zwykle wykonujemy konkatentację ciągów w następujący sposób:

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

Oczywiście znacznie bardziej czytelne jest:

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

Ale eksperci JS twierdzą, że +operator jest mniej wydajny niż StringBuffer.append(). Czy to prawda?


93
W javascript nie ma StringBuffera
Tomas

7
Don, mówiłeś o Javie?
James McMahon

Z mojego doświadczenia wynika [].join(''), że zachowuje się naprawdę
sztywno

1
Wiem, że podstawowe pytanie dotyczy konkatenacji ciągów, ale należy zachować ostrożność podczas tworzenia takich elementów html. Twój przykład może się zepsuć, jeśli urlzawiera 'lub \n.
styfle

Odpowiedzi:


46

Internet Explorer jest jedyną przeglądarką, która naprawdę cierpi z tego powodu w dzisiejszym świecie. (Wersje 5, 6 i 7 były wolne dla psów. 8 nie wykazuje takiej samej degradacji). Co więcej, IE staje się wolniejszy i wolniejszy, im dłuższa jest twoja struna.

Jeśli masz długie ciągi do połączenia, zdecydowanie użyj techniki array.join. (Lub jakieś opakowanie StringBuffer dookoła tego dla czytelności.) Ale jeśli twoje łańcuchy są krótkie, nie przejmuj się.


102

Twój przykład nie jest dobry, ponieważ jest bardzo mało prawdopodobne, aby występ był znacząco inny. W twoim przykładzie czytelność powinna przewyższać wydajność, ponieważ wzrost wydajności jednego z drugim jest pomijalny. Zalety tablicy (StringBuffer) są widoczne tylko wtedy, gdy wykonujesz wiele konkatentacji. Nawet wtedy Twój przebieg może się bardzo różnić w zależności od przeglądarki.

Oto szczegółowa analiza wydajności, która pokazuje wydajność przy użyciu różnych metod konkatenacji JavaScript w wielu różnych przeglądarkach; Analiza wydajności strun

join () raz, concat () raz, join () for, + = for, concat () for

Więcej:
Ajaxian >> Wydajność ciągów w IE: Array.join vs + = kontynuacja


9
Jeśli chodzi o wykres, na wypadek, gdyby nie był oczywisty; niższy jest lepszy.
Teekin

1
„Po pierwsze, jeśli chodzi o poprawę wydajności w IE7, nie musimy już rozważać użycia alternatywnej ścieżki podczas wykonywania operacji na łańcuchach na dużą skalę; użycie Array.join w sytuacji iteracyjnej nie daje większych korzyści niż użycie + = w tej samej sytuacji. Ponadto różnice w porównaniu z IE6 były na tyle niewielkie, że można było nie zawracać sobie głowy rozwidlaniem tej konkretnej wersji ”.
Chris S,

2
@Chris, to nieprawda. Porównaj te dwa skrzypce w IE7 : jsfiddle.net/9uS4n/5 (szybko) vs. jsfiddle.net/9uS4n/2 (wolno). Wydaje się, że join()technika ta poprawia wydajność co najmniej 1000 razy .
Kirk Woll,

Niezłe wyjaśnienie. Proszę również zapoznać się z tym: iliadraznin.com/2012/03/…
will824

37

Tak, to prawda, ale nie powinno cię to obchodzić. Wybierz ten, który jest łatwiejszy do odczytania. Jeśli musisz przetestować swoją aplikację, skup się na wąskich gardłach.

Domyślam się, że konkatenacja ciągów nie będzie Twoim wąskim gardłem.


31

Uzgodniono z Michaelem Harenem .

Rozważ także użycie tablic i łączenie, jeśli wydajność jest rzeczywiście problemem.

var buffer = ["<a href='", url, "'>click here</a>"];
buffer.push("More stuff");
alert(buffer.join(""));

3
Wiem, że wybrano prawidłową odpowiedź, ale ta odpowiedź ma bardziej przydatny przykład.
Jason Sperske

1
Łał po prostu łał. Porównaj te dwa skrzypce w IE7 : jsfiddle.net/9uS4n/5 (szybko) vs. jsfiddle.net/9uS4n/2 (wolno). Wydaje się, że ta technika poprawia wydajność co najmniej 1000 razy.
Kirk Woll,

@KirkWoll: W przyszłości może zechcesz użyć jsPerf , abyśmy mogli łatwo porównać wyniki.
rvighne

ostatnio też to robiłem, podobny styl kodu do .NET StringBuilder, var sb = []; sb.push ("sekcja 1"); sb.push ("sekcja 2"); return sb.join ('');
Sam Jones


18

Spróbuj tego:

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

Cóż, post, do którego umieściłeś link w swojej odpowiedzi, ma na celu obalenie „mitu” Array.join, który sugeruje moja odpowiedź. Więc może nie. Po prostu opublikowałem coś, co w praktyce okazało się szybsze.
Rahul

uwielbiam tę metodę łączenia ciągów.
bkwdesign

8

Jak już zauważyli niektórzy użytkownicy: Nie ma to znaczenia dla małych ciągów.

A nowe silniki JavaScript w Firefoksie, Safari lub Google Chrome optymalizują tak

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

jest tak szybki jak

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

8

JavaScript nie ma natywnego obiektu StringBuffer, więc zakładam, że pochodzi on z biblioteki, której używasz, lub z funkcji nietypowego środowiska hosta (tj. Nie z przeglądarki).

Wątpię, by biblioteka (napisana w JS) wyprodukowała coś szybciej, chociaż natywny obiekt StringBuffer mógłby. Ostateczną odpowiedź można znaleźć za pomocą profilera (jeśli korzystasz z przeglądarki, Firebug zapewni Ci profiler dla silnika JS znajdującego się w Firefoksie).


6

Mówiąc słowami Knutha, „przedwczesna optymalizacja jest źródłem wszelkiego zła!” Tak czy inaczej niewielka różnica najprawdopodobniej nie będzie miała większego wpływu na koniec; Wybrałbym ten bardziej czytelny.


1
Tradycyjnie StringBuffer jest używany w konkatenacji, ponieważ pierwszy ma złożoność czasową O (N), a drugi jako O (N ^ 2), dlatego różnica jest znacząca dla dużego N (ale nie dla małego N). W każdym razie scenariusz O (N ^ 2) może nie mieć miejsca w JavaScript, w zależności od używanego środowiska.
redcalx

4

Łatwiejsza do odczytania metoda oszczędza dostrzegalną dla ludzi ilość czasu podczas przeglądania kodu, podczas gdy metoda „szybsza” marnuje tylko niezauważalną i prawdopodobnie znikomą ilość czasu, gdy ludzie przeglądają stronę.

Wiem, że ten post jest kiepski, ale przypadkowo opublikowałem coś zupełnie innego, myśląc, że to inny wątek i nie wiem, jak usunąć posty. Mój błąd...


3

Bardzo łatwo jest skonfigurować szybki test porównawczy i sprawdzić różnice w wydajności JavaScript za pomocą jspref.com . Które prawdopodobnie nie było w pobliżu, kiedy zadano to pytanie. Ale osoby, które natkną się na to pytanie, powinny spojrzeć na stronę.

Zrobiłem szybki test różnych metod konkatenacji na http://jsperf.com/string-concat-methods-test .


Sądząc po tym, wygląda na to, że obecnie konkatenacja z operatorem + jest zdecydowanie najlepszym rozwiązaniem. Chyba że źle to czytam. Co jest całkowicie prawdopodobne.
Richard

2

Lubię używać funkcjonalnego stylu, takiego jak:

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")
    ]
  )
)

Ten styl wygląda na czytelny i przejrzysty. Prowadzi do tworzenia narzędzi, które zmniejszają liczbę powtórzeń w kodzie.

To również ma tendencję do automatycznego używania ciągów pośrednich.


1

O ile wiem, każda konkatenacja oznacza realokację pamięci. Zatem problemem nie jest operator, który to robił, rozwiązaniem jest zmniejszenie liczby konkatenacji. Na przykład wykonaj konkatenacje poza strukturami iteracji, kiedy możesz.


To właściwie nie jest zła rada, nie wiem, dlaczego tak bardzo ją odrzucono. Wiem, że nie odpowiada na konkretne pytanie, ale zasługuje na uznanie, jako ogólnie dobra rada.
powiek

0

Tak, zgodnie ze zwykłymi wzorcami. Np .: http://mckoss.com/jscript/SpeedTrial.htm .

Ale w przypadku małych strun nie ma to znaczenia. Będziesz dbał tylko o występy na bardzo dużych strunach. Co więcej, w większości skryptów JS szyjka butelki rzadko znajduje się na manipulacjach struną, ponieważ jest jej za mało.

Lepiej obserwuj manipulację DOM.


Link nie żyje .. https://web.archive.org/web/20150912072015/http://mckoss.com/jscript/SpeedTrial.htm wskazuje na wersję archiwum internetowego.
Tony
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.