toán tử + có hiệu suất kém hơn StringBuffer.append ()


91

Trong nhóm của tôi, chúng tôi thường thực hiện đồng nhất chuỗi như thế này:

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

Rõ ràng là những điều sau đây dễ đọc hơn:

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

Nhưng các chuyên gia JS cho rằng +toán tử này hoạt động kém hơn StringBuffer.append(). Điều này có thực sự đúng?


92
Không có StringBuffer trong javascript
Tomas

7
Don, bạn đang đề cập đến Java?
James McMahon,

Kinh nghiệm của tôi đã được rằng [].join('')đã thể hiện một số hành vi thực sự có dây, vì vậy tôi FEL trở lại +: - /
martyglaubitz

1
Tôi biết câu hỏi cơ bản ở đây là về nối chuỗi nhưng bạn nên thận trọng khi tạo các phần tử html như thế này. Ví dụ của bạn có thể bị hỏng nếu urlchứa 'hoặc \n.
súng trường vào

Câu trả lời:


46

Internet Explorer là trình duyệt duy nhất thực sự gặp phải vấn đề này trong thế giới ngày nay. (Các phiên bản 5, 6 và 7 rất chậm. 8 không cho thấy sự xuống cấp tương tự.) Hơn nữa, IE ngày càng chậm hơn khi chuỗi của bạn dài hơn.

Nếu bạn có các chuỗi dài để nối thì chắc chắn sử dụng kỹ thuật array.join. (Hoặc một số trình bao bọc StringBuffer xung quanh điều này, để dễ đọc.) Nhưng nếu chuỗi của bạn ngắn, đừng bận tâm.


102

Ví dụ của bạn không phải là một ví dụ tốt ở chỗ rất ít khả năng hiệu suất sẽ khác biệt đáng kể. Trong ví dụ của bạn, khả năng đọc sẽ vượt trội hơn hiệu suất vì mức tăng hiệu suất của cái này so với cái kia là không thể bỏ qua. Lợi ích của một mảng (StringBuffer) chỉ rõ ràng khi bạn thực hiện nhiều phép tương đồng. Ngay cả sau đó số dặm của bạn có thể rất phụ thuộc vào trình duyệt của bạn.

Dưới đây là phân tích hiệu suất chi tiết cho thấy hiệu suất sử dụng tất cả các phương pháp nối JavaScript khác nhau trên nhiều trình duyệt khác nhau; Hiệu suất chuỗi một phân tích

tham gia () một lần, concat () một lần, tham gia () cho, + = cho, concat () cho

Thêm:
Ajaxian >> Hiệu suất chuỗi trong IE: Array.join vs + = tiếp tục


9
Về biểu đồ, trong trường hợp nó không rõ ràng; thấp hơn là tốt hơn.
Teekin

1
"Trước tiên, với những cải tiến về hiệu suất với IE7, chúng tôi không còn cần phải cân nhắc sử dụng một đường dẫn thay thế khi thực hiện các hoạt động chuỗi quy mô lớn; sử dụng Array.join trong một tình huống lặp lại không mang lại cho bạn lợi thế nào lớn hơn việc sử dụng + = trong cùng một tình huống. Ngoài ra, sự khác biệt với IE6 là đủ nhỏ để cho phép bạn không cần phải phân biệt phiên bản cụ thể đó. "
Chris S

2
@Chris, không đúng đâu. So sánh hai trò chơi này trong IE7 : jsfiddle.net/9uS4n/5 (nhanh) so với jsfiddle.net/9uS4n/2 (chậm). Có vẻ như hiệu suất được cải thiện ít nhất 1000 lần khi sử dụng join()kỹ thuật này.
Kirk Woll

Lời giải thích hay. Xin vui lòng xem xét điều này: iliadraznin.com/2012/03/...
will824

37

Vâng, nó đúng nhưng bạn không nên quan tâm. Đi với cái dễ đọc hơn. Nếu bạn phải đánh giá ứng dụng của mình, thì hãy tập trung vào các điểm nghẽn.

Tôi đoán rằng nối chuỗi sẽ không phải là nút thắt cổ chai của bạn.


31

Đồng ý với Michael Haren .

Cũng nên xem xét việc sử dụng các mảng và nối nếu hiệu suất thực sự là một vấn đề.

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

3
Tôi biết rằng một câu trả lời đúng đã được chọn, nhưng câu trả lời này có một ví dụ hữu ích hơn.
Jason Sperske

1
Chà, thật tuyệt. So sánh hai trò chơi này trong IE7 : jsfiddle.net/9uS4n/5 (nhanh) so với jsfiddle.net/9uS4n/2 (chậm). Có vẻ như hiệu suất được cải thiện ít nhất 1000 lần khi sử dụng kỹ thuật này.
Kirk Woll

@KirkWoll: Có thể muốn sử dụng jsPerf trong tương lai để chúng tôi có thể dễ dàng so sánh kết quả.
rvighne

Tôi cũng đã làm điều này gần đây, kiểu mã tương tự như .NET StringBuilder, var sb = []; sb.push ("phần 1"); sb.push ("phần 2"); return sb.join ('');
Sam Jones

Điều này jsPerf jsperf.com/join-concat/2 được đề cập tại: stackoverflow.com/questions/16696632/… dường như chỉ ra rằng +=nhanh hơn.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

18

Thử cái này:

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

Chà, bài đăng mà bạn liên kết đến trong câu trả lời của mình cố gắng bác bỏ "huyền thoại" của Array.join mà câu trả lời của tôi gợi ý. Vì vậy, có lẽ là không. Tôi chỉ đăng những gì tôi thấy để nhanh hơn trong thực tế.
Rahul

yêu thích phương thức này của chuỗi concat.
bkwdesign

8

Giống như một số người dùng đã lưu ý: Điều này không liên quan đến các chuỗi nhỏ.

Và các công cụ JavaScript mới trong Firefox, Safari hoặc Google Chrome sẽ tối ưu hóa

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

nhanh như

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

8

JavaScript không có đối tượng StringBuffer gốc, vì vậy tôi giả sử đây là từ thư viện bạn đang sử dụng hoặc một tính năng của môi trường máy chủ lưu trữ bất thường (tức là không phải trình duyệt).

Tôi nghi ngờ một thư viện (được viết bằng JS) sẽ tạo ra bất kỳ thứ gì nhanh hơn, mặc dù một đối tượng StringBuffer gốc có thể. Câu trả lời cuối cùng có thể được tìm thấy với một trình biên dịch (nếu bạn đang chạy trong một trình duyệt thì Firebug sẽ cung cấp cho bạn một hồ sơ cho công cụ JS được tìm thấy trong Firefox).


6

Theo lời của Knuth, "tối ưu hóa quá sớm là gốc rễ của mọi điều ác!" Sự khác biệt nhỏ dù theo cách nào thì cuối cùng cũng không có nhiều tác dụng; Tôi sẽ chọn cái dễ đọc hơn.


1
Theo truyền thống, StringBuffer được sử dụng thay vì nối vì cái trước có độ phức tạp thời gian là O (N) trong khi cái sau là O (N ^ 2), do đó sự khác biệt là đáng kể đối với N lớn (nhưng không phải đối với N nhỏ). Trong mọi trường hợp, kịch bản O (N ^ 2) có thể không phải là trường hợp trong JavaScript tùy thuộc vào môi trường sử dụng.
redcalx

4

Phương pháp dễ đọc hơn giúp con người tiết kiệm được lượng thời gian có thể nhận thấy khi xem mã, trong khi phương pháp "nhanh hơn" chỉ lãng phí lượng thời gian không thể nhận thấy và có thể là không đáng kể khi mọi người duyệt trang.

Tôi biết bài đăng này là khập khiễng, nhưng tôi đã vô tình đăng một thứ hoàn toàn khác vì nghĩ rằng đây là một chủ đề khác và tôi không biết làm thế nào để xóa bài đăng. Lỗi của tôi...


3

Khá dễ dàng để thiết lập một điểm chuẩn nhanh và kiểm tra các biến thể hiệu suất của Javascript bằng cách sử dụng jspref.com . Mà có lẽ đã không xảy ra khi câu hỏi này được hỏi. Nhưng đối với những người vấp phải câu hỏi này, họ nên xem xét trang web.

Tôi đã thực hiện một bài kiểm tra nhanh các phương pháp nối khác nhau tại http://jsperf.com/string-concat-methods-test .


Đánh giá theo điều đó, có vẻ như ngày nay việc nối với toán tử + chắc chắn là một cách để đi. Trừ khi tôi đọc nhầm. Điều đó là hoàn toàn chính đáng.
Richard

2

Tôi thích sử dụng phong cách chức năng, chẳng hạn như:

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

Phong cách này trông dễ đọc và minh bạch. Nó dẫn đến việc tạo ra các tiện ích làm giảm sự lặp lại trong mã.

Điều này cũng có xu hướng sử dụng các chuỗi trung gian tự động.


1

Theo như tôi biết, mọi phép nối đều ngụ ý một sự tái phân bổ bộ nhớ. Vì vậy, vấn đề không phải là toán tử được sử dụng để làm điều đó, giải pháp là giảm số lượng các phép nối. Ví dụ, hãy thực hiện các phép nối bên ngoài cấu trúc lặp khi bạn có thể.


Đây thực sự không phải là lời khuyên tồi, tôi không biết tại sao nó lại bị bỏ phiếu nhiều như vậy. Tôi biết nó không trả lời câu hỏi cụ thể, nhưng nó xứng đáng được công nhận là lời khuyên tốt.
mí mắt,

0

Có, theo tiêu chuẩn thông thường. EG: http://mckoss.com/jscript/SpeedTrial.htm .

Nhưng đối với các dây nhỏ, điều này không liên quan. Bạn sẽ chỉ quan tâm đến các buổi biểu diễn trên dây rất lớn. Hơn nữa, trong hầu hết các tập lệnh JS, phần cổ chai hiếm khi có trong các thao tác chuỗi vì không có đủ nó.

Tốt hơn bạn nên xem thao tác DOM.


Liên kết đã chết .. https://web.archive.org/web/20150912072015/http://mckoss.com/jscript/SpeedTrial.htm trỏ đến phiên bản lưu trữ web.
Tony,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.