เป็นตัวดำเนินการ + ที่มีประสิทธิภาพน้อยกว่า 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 อ้างว่า+ผู้ประกอบการเป็น performant StringBuffer.append()น้อยกว่า นี่มันเรื่องจริงเหรอ?


93
ไม่มี StringBuffer ใน javascript
Tomas

7
Don คุณหมายถึง Java หรือไม่?
James McMahon

ประสบการณ์ของฉันคือ[].join('')ได้แสดงพฤติกรรมแบบใช้สายจริงๆดังนั้นฉันจึงกลับไปที่ +: - /
martyglaubitz

1
ฉันรู้ว่าคำถามพื้นฐานที่นี่เกี่ยวกับการต่อสตริง แต่คุณควรใช้ความระมัดระวังในการสร้างองค์ประกอบ html เช่นนี้ ตัวอย่างของคุณอาจแตกได้หากurlมี'หรือ\n.
styfle

คำตอบ:


46

Internet Explorer เป็นเบราว์เซอร์เดียวที่ได้รับผลกระทบจากสิ่งนี้ในโลกปัจจุบัน (เวอร์ชัน 5, 6 และ 7 เป็นสุนัขที่ทำงานช้า 8 ไม่แสดงการลดระดับเดียวกัน) ยิ่งไปกว่านั้น IE ทำงานช้าลงและช้าลงยิ่งสตริงของคุณยาวขึ้น

หากคุณมีสตริงที่ยาวเพื่อเชื่อมต่อให้ใช้เทคนิค array.join (หรือบางส่วนของ StringBuffer wrapper รอบนี้เพื่อให้อ่านง่าย) แต่ถ้าสตริงของคุณสั้นก็ไม่ต้องกังวล


102

ตัวอย่างของคุณไม่ดีตรงที่มีโอกาสน้อยมากที่ประสิทธิภาพจะแตกต่างกันอย่างเห็นได้ชัด ในความสามารถในการอ่านตัวอย่างของคุณควรมีประสิทธิภาพมากกว่าเนื่องจากประสิทธิภาพที่เพิ่มขึ้นของหนึ่งเทียบกับอีกด้านหนึ่งนั้นน้อยมาก ประโยชน์ของอาร์เรย์ (StringBuffer) จะปรากฏเฉพาะเมื่อคุณทำการเรียงต่อกันหลาย ๆ ถึงแม้ว่าระยะทางของคุณอาจขึ้นอยู่กับเบราว์เซอร์ของคุณ

นี่คือการวิเคราะห์ประสิทธิภาพโดยละเอียดที่แสดงประสิทธิภาพโดยใช้วิธีการเชื่อมต่อ JavaScript ที่แตกต่างกันทั้งหมดในเบราว์เซอร์ต่างๆ การวิเคราะห์ประสิทธิภาพสตริง

join () ครั้งเดียว concat () ครั้งเดียว join () for + = for concat () for

เพิ่มเติม:
Ajaxian >> String Performance ใน IE: Array.join vs + = ต่อ


9
เกี่ยวกับกราฟในกรณีที่ไม่ชัดเจน ต่ำกว่าดีกว่า
Teekin

1
"สิ่งแรกอันดับแรกในการปรับปรุงประสิทธิภาพด้วย IE7 เราไม่จำเป็นต้องพิจารณาใช้เส้นทางสำรองอีกต่อไปเมื่อดำเนินการกับสตริงขนาดใหญ่การใช้ Array.join ในสถานการณ์ซ้ำ ๆ จะทำให้คุณไม่มีข้อได้เปรียบที่สำคัญไปกว่าการใช้ + = ในสถานการณ์เดียวกัน นอกจากนี้ความแตกต่างของ IE6 ก็เล็กน้อยเพียงพอที่จะทำให้คุณไม่ต้องกังวลกับการใช้งานสำหรับเวอร์ชันเฉพาะนั้น "
Chris S

2
@ คริสว่าไม่จริง เปรียบเทียบซอสองตัวนี้ในIE7 : jsfiddle.net/9uS4n/5 (เร็ว) กับjsfiddle.net/9uS4n/2 (ช้า) ดูเหมือนว่าจะมีการปรับปรุงประสิทธิภาพอย่างน้อย 1,000 เท่าโดยใช้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
ฉันรู้ว่าได้เลือกคำตอบที่ถูกต้องแล้ว แต่คำตอบนี้มีตัวอย่างที่เป็นประโยชน์มากกว่า
Jason Sperske

1
ว้าวแค่ว้าว เปรียบเทียบซอสองตัวนี้ในIE7 : jsfiddle.net/9uS4n/5 (เร็ว) กับjsfiddle.net/9uS4n/2 (ช้า) ดูเหมือนว่าจะมีการปรับปรุงประสิทธิภาพอย่างน้อย 1,000 เท่าโดยใช้เทคนิคนี้
Kirk Woll

@KirkWoll: อาจต้องการใช้jsPerfในอนาคตเพื่อให้เราสามารถเปรียบเทียบผลลัพธ์ได้อย่างง่ายดาย
rvighne

เมื่อเร็ว ๆ นี้ฉันก็ทำเช่นกันลักษณะโค้ดที่คล้ายกันกับ. NET StringBuilder, var sb = []; sb.push ("ส่วนที่ 1"); sb.push ("ส่วนที่ 2"); กลับ sb.join ('');
Sam Jones

jsPerf นี้jsperf.com/join-concat/2กล่าวถึงที่: stackoverflow.com/questions/16696632/...ดูเหมือนจะบ่งบอกว่า+=จะเร็วขึ้น
Ciro Santilli 郝海东冠状病六四事件法轮功

18

ลองสิ่งนี้:

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

โพสต์ที่คุณเชื่อมโยงในคำตอบของคุณพยายามที่จะหักล้าง "ตำนาน" ของ Array.join ซึ่งคำตอบของฉันแนะนำโดยเฉพาะ ดังนั้นอาจจะไม่ ฉันแค่โพสต์สิ่งที่ฉันเห็นว่าเร็วกว่าในทางปฏิบัติ
Rahul

ชอบวิธีการเชื่อมต่อสตริงนี้
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

ในคำพูดของ Knuth "การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นรากเหง้าของความชั่วร้ายทั้งหมด!" การเบี่ยงเบนเล็กน้อยทางใดทางหนึ่งส่วนใหญ่จะไม่มีผลมากนักในตอนท้าย ฉันจะเลือกอันที่อ่านง่ายกว่า


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


เมื่อพิจารณาจากว่าในปัจจุบันการเชื่อมต่อกับตัวดำเนินการ + เป็นหนทางที่จะไป เว้นแต่ฉันจะอ่านผิด ซึ่งเป็นไปได้ทั้งหมด
Richard

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

ใช่ตามเกณฑ์มาตรฐานปกติ EG: http://mckoss.com/jscript/SpeedTrial.htm

แต่สำหรับสายเล็กสิ่งนี้ไม่เกี่ยวข้อง คุณจะสนใจเฉพาะการแสดงบนสตริงขนาดใหญ่เท่านั้น ยิ่งไปกว่านั้นในสคริปต์ JS ส่วนใหญ่คอขวดมักไม่ค่อยมีการปรับแต่งสตริงเนื่องจากมีไม่เพียงพอ

คุณควรดูการจัดการ DOM ดีกว่า


ลิงก์ตาย .. https://web.archive.org/web/20150912072015/http://mckoss.com/jscript/SpeedTrial.htmชี้ไปที่เวอร์ชันที่เก็บถาวรของเว็บ
Tony
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.