jQuery: ความจำเพาะของตัวเลือกเพิ่มประสิทธิภาพด้วยการมอบหมาย .on() หรือไม่

มีประสิทธิภาพเพิ่มขึ้นเมื่อเพิ่มความเฉพาะเจาะจงในเหตุการณ์ที่ได้รับมอบหมายที่ผูกกับ .on() หรือไม่

เราจะทดสอบสิ่งนี้ได้อย่างไร?

ตัวอย่างเช่น คำสั่งที่สองมีประสิทธิภาพมากกว่าคำสั่งแรก:

$('.foo').on('mouseenter', ':has(.other)', function (e) {
    console.log(e);
});

$('.bar').on('mouseenter', 'button:has(.other)', function (e) {
    console.log(e);
});

$('.foo').on('mouseenter', ':has(.other)', function (e) {
  console.log(e);
});

$('.bar').on('mouseenter', 'button:has(.other)', function (e) {
  console.log(e);
});
.foo, .bar {
  margin: 2em auto;
  text-align: center;
}
<div class="foo">
  <button type="button">Hello
    <span class="other">World</span>
  </button>
</div>

<div class="bar">
  <button type="button">Hello
    <span class="other">World</span>
  </button>
</div>

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

อัปเดต

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

ความโน้มเอียงของฉันคือการถือว่าไม่มีเพราะทุกเหตุการณ์จะต้องฟองขึ้นไปที่องค์ประกอบที่ถูกผูกไว้ก่อนที่จะถูกตรวจสอบกับตัวเลือกที่ได้รับมอบหมาย

แต่มีวิธีทดสอบสิ่งนี้หรือไม่?


person gfullam    schedule 12.02.2015    source แหล่งที่มา
comment
ลองใช้การทดสอบ jsperf แล้วหรือยัง?   -  person j08691    schedule 13.02.2015
comment
หากมีสิ่งใด ฉันคิดว่าเวอร์ชันที่ 2 จะมีประสิทธิภาพน้อยลงโดยประมาท พวกเขาทั้งสองจะต้องพูดถึงบรรพบุรุษต่อไป และเวอร์ชันที่สองจำเป็นต้องตรวจสอบประเภทโหนดและการมีอยู่ของคลาส   -  person JMM    schedule 13.02.2015
comment
ฉันจะรันการทดสอบ jsperf กับตัวอย่างเฉพาะนี้ได้อย่างไร jsperf ไม่เพียงทดสอบประสิทธิภาพรันไทม์ เช่น การดำเนินการเชื่อมโยงเอง ซึ่งตรงข้ามกับการจัดการเหตุการณ์จากการโต้ตอบของผู้ใช้ใช่หรือไม่   -  person gfullam    schedule 13.02.2015
comment
c2.com/cgi/wiki?PrematureOptimization   -  person undefined    schedule 13.02.2015
comment
ฮ่าๆ. นี่ไม่ใช่การคลอดก่อนกำหนด ฉันกำลังทำงานกับแอประดับองค์กรที่อาจมีองค์ประกอบ DOM หลายพันรายการให้สำรวจ นี่คือตัวอย่างที่จับคู่กันเพื่อให้แน่ใจ   -  person gfullam    schedule 13.02.2015
comment
ฉันควรชี้แจงว่าฉันไม่ต้องการทำความเข้าใจผลการปฏิบัติงานของการใช้การมอบหมาย ฉันหวังว่าจะเข้าใจความหมายของประสิทธิภาพของการใช้การมอบหมายด้วย mouseenter และหากมีประสิทธิภาพเพิ่มขึ้นโดยใช้ตัวเลือกที่เฉพาะเจาะจงมากขึ้นสำหรับการมอบหมาย ความโน้มเอียงของฉันคือการถือว่าไม่มีเพราะทุกเหตุการณ์จะต้องฟองขึ้นไปที่องค์ประกอบที่ถูกผูกไว้ก่อนที่จะถูกตรวจสอบกับตัวเลือกที่ได้รับมอบหมาย แต่มีวิธีทดสอบสิ่งนี้หรือไม่?   -  person gfullam    schedule 13.02.2015
comment
ฉันขอแนะนำว่าโดยทั่วไปแล้ว การใช้ :has ในการเรียก closest (เหมือนกับที่ on ทำเบื้องหลัง) จะมีประสิทธิภาพ เลวร้าย ฉันจะทดสอบหา button ในตัวเลือกแล้วใช้เมธอด .has() ในการโทรกลับ   -  person lonesomeday    schedule 13.02.2015
comment
@lonesomeday นั่นสมเหตุสมผลแล้ว แต่น่าเสียดายที่ฉันอาจผูกโดยตรงกับองค์ประกอบคอนเทนเนอร์ที่จะรับปุ่มในภายหลังเท่านั้น เนื้อหาของคอนเทนเนอร์นี้อาจแสดงผลซ้ำกี่ครั้งก็ได้ ดังนั้นการมอบหมายจึงเป็นสิ่งจำเป็น   -  person gfullam    schedule 13.02.2015
comment
@gfullam ฉันแน่ใจว่าการมอบหมายเป็นตัวเลือกที่ถูกต้อง อย่างไรก็ตาม ฉันจะพยายามอย่างเต็มที่เพื่อให้แน่ใจว่า :has selector ไม่ได้อยู่ในของคุณ สตริงตัวเลือก มันเป็นตัวเลือก jQuery ไม่ใช่เบราว์เซอร์ดั้งเดิมและช้ามาก คุณกำลังใช้มันกับทุกองค์ประกอบในแผนผัง หากคุณทำการทดสอบอื่น ให้พูดว่า button จากนั้นใช้ .has ฟังก์ชัน เพื่อทดสอบองค์ประกอบนั้น องค์ประกอบนั้นจะมี ประสิทธิภาพที่ดีขึ้นมากเนื่องจากสามารถใช้ความสามารถภายในของเบราว์เซอร์ได้ดีขึ้น   -  person lonesomeday    schedule 13.02.2015
comment
@lonesomeday ฉันใช้ความพยายามอย่างมากในตอนแรกเพื่อหลีกเลี่ยงการมอบหมายเพราะฉันต้องผูกกับพาเรนต์ของตัวเลือกคลาสลูกที่รู้จัก น่าเสียดายที่วิธีเดียวที่จะทำสิ่งนี้ได้คือด้วย :has เพราะคุณไม่สามารถโยง .has กับตัวเลือกที่ได้รับมอบหมายได้ - สามารถทำได้ เชื่อมโยงกับองค์ประกอบ DOM ที่มีอยู่เท่านั้น และในขณะที่เชื่อมโยง องค์ประกอบนั้นจะไม่อยู่ที่นั่น เนื่องจากการใช้ :has ของฉัน ฉันจึงกังวลเกี่ยวกับการค้นหาประสิทธิภาพอื่นๆ ที่เพิ่มขึ้น สิ่งสำคัญสำหรับฉันคือต้องทำความเข้าใจว่าเกิดอะไรขึ้นและจะทดสอบประสิทธิภาพในสถานการณ์นี้อย่างไร   -  person gfullam    schedule 13.02.2015
comment
@gfullam ฉันตระหนักดีว่า ฉันกำลังบอกว่าคุณควรพยายามนำ :has ออกจากตัวเลือกและทำการทดสอบในการเรียกกลับเหตุการณ์ มันจะมีประสิทธิภาพดีขึ้นมาก ดูสองตัวอย่างนี้: มีฟังก์ชันการทำงานที่เทียบเท่ากัน แต่ตัวอย่างแรกมีประสิทธิภาพที่ดีกว่ามาก   -  person lonesomeday    schedule 13.02.2015
comment
@lonesomeday ฉันชอบตัวอย่างนั้น และมันใกล้จะตอบคำถามของฉันแล้ว คุณสามารถโพสต์มันเป็นคำตอบพร้อมคำอธิบายว่า '' เหตุใด '' ฟังก์ชั่นหนึ่งจึงมีประสิทธิภาพมากกว่าฟังก์ชั่นอื่น ๆ ได้หรือไม่? คุณจะทราบความแตกต่างด้านประสิทธิภาพระหว่างทั้งสองได้อย่างไร?   -  person gfullam    schedule 13.02.2015
comment
ในที่สุดก็พบวิธีกำหนดการทดสอบ jsperf ที่แสดงให้เห็นว่าการใช้ :has ในตัวเลือกนั้นบ่อยกว่า (ในการทดสอบซ้ำ) มีประสิทธิภาพมากกว่าการใช้ .has ในตัวจัดการ นอกจากนี้ยังแสดงให้เห็นว่าความจำเพาะที่เพิ่มขึ้น เช่นเดียวกับใน button:has ในตัวเลือก ทำให้ประสิทธิภาพได้รับการปรับปรุงอย่างต่อเนื่อง ดู: jsperf.com/has-filter-in-delegated-event-selector< /ก>   -  person gfullam    schedule 03.05.2015


คำตอบ (1)


ความจำเพาะช่วย…นิดหน่อย

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

ในการทดสอบบางอย่าง ความแตกต่างมีน้อยเพียงพอและอยู่ภายในขอบเขตของข้อผิดพลาดที่ถือว่าเทียบเท่ากันทางสถิติ

ตัวเลือกการกรองในตัวจัดการทำให้เจ็บ

แต่ผลลัพธ์ที่น่าประหลาดใจที่สุดคือการทดสอบเสริมครั้งที่สามที่แนะนำโดยหนึ่งในผู้แสดงความคิดเห็นข้างต้น ซึ่งนำ :has() ออกจากตัวเลือกและแทนที่ด้วยการตรวจสอบ .has() ในฟังก์ชันการโทรกลับ ซึ่งดำเนินการช้ากว่าการใช้ :has() ในตัวเลือกอย่างสม่ำเสมอ — บ่อยครั้ง 100 การดำเนินการต่อวินาทีหรือมากกว่า

นี่เป็นสิ่งที่ไม่สำคัญน้อยกว่าและน่าทึ่งเป็นพิเศษเมื่อพิจารณาว่า เอกสารประกอบ jQuery สำหรับ :has() ระบุว่าคุณควร คาดหวังประสิทธิภาพที่ดีขึ้นที่นี่:

เนื่องจาก :has() เป็นส่วนขยาย jQuery และไม่ได้เป็นส่วนหนึ่งของข้อกำหนด CSS การสืบค้นที่ใช้ :has() จึงไม่สามารถใช้ประโยชน์จากการเพิ่มประสิทธิภาพที่ได้รับจากเมธอด DOM querySelectorAll() ดั้งเดิมได้ เพื่อประสิทธิภาพที่ดีขึ้นในเบราว์เซอร์สมัยใหม่ ให้ใช้ $( "your-pure-css-selector" ).has( selector/DOMElement ) แทน

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


สูตรทดสอบ

ในการกำหนดการทดสอบ เกณฑ์มาตรฐานการเชื่อมโยงเหตุการณ์สามรายการได้รับการกำหนดค่าและนำไปใช้กับมาร์กอัป HTML เดียวกัน จากนั้นจึงใช้กรณีทดสอบการทริกเกอร์เหตุการณ์เดียวกัน — จำลองผู้ใช้วางเมาส์เหนือองค์ประกอบต่างๆ ที่ได้รับมอบสิทธิ์และไม่ได้รับมอบสิทธิ์บนหน้าจอ — ถูกนำไปใช้กับแต่ละรายการ เกณฑ์มาตรฐานสามประการสำหรับการเปรียบเทียบ

เกณฑ์มาตรฐาน 1:

    $('.foo').on('mouseenter', ':has(.other)', function(e) {
      console.log(e);
    });

เกณฑ์มาตรฐาน 2:

    $('.foo').on('mouseenter', 'button:has(.other)', function(e) {
      console.log(e);
    });

เกณฑ์มาตรฐาน 3:

    $('.foo').on('mouseenter', 'button', function(e) {
      if ($(this).has('.other').length) {
        console.log(e);
      }
    });

HTML:

<div class="foo">
    <button type="button" id="A">some text</button>
    <button type="button" id="B"><span class="other">some text</span></button>
    <div id="C">some text</div>
</div>

กรณีทดสอบ:

$('#A').trigger('mouseenter');
$('#B').trigger('mouseenter');
$('#C').trigger('mouseenter');

ภาพหน้าจอของตารางแสดงผลการทดสอบ JSPerf

person gfullam    schedule 04.05.2015