หากลบองค์ประกอบ DOM แล้วผู้ฟังจะถูกลบออกจากหน่วยความจำด้วยหรือไม่


คำตอบ:


307

เบราว์เซอร์สมัยใหม่

JavaScript ธรรมดา

หากองค์ประกอบ DOM ที่ถูกลบนั้นไม่มีการอ้างอิง (ไม่มีการอ้างอิงที่ชี้ไปที่มัน) ใช่ - องค์ประกอบนั้นจะถูกเก็บรวบรวมโดยตัวรวบรวมขยะเช่นเดียวกับตัวจัดการเหตุการณ์ / ผู้ฟังที่เกี่ยวข้อง

var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
b = null; 
// A reference to 'b' no longer exists 
// Therefore the element and any event listeners attached to it are removed.

อย่างไรก็ตาม; หากมีการอ้างอิงที่ยังคงชี้ไปที่องค์ประกอบดังกล่าวองค์ประกอบและผู้ฟังเหตุการณ์จะถูกเก็บไว้ในหน่วยความจำ

var a = document.createElement('div');
var b = document.createElement('p'); 
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b); 
// A reference to 'b' still exists 
// Therefore the element and any associated event listeners are still retained.

jQuery

มันจะยุติธรรมที่จะคิดว่าวิธีการที่เกี่ยวข้องใน jQuery (เช่นremove()) จะทำงานในลักษณะเดียวกัน (การพิจารณาremove()นั้นถูกเขียนโดยใช้removeChild()ตัวอย่าง)

แต่นี้ไม่เป็นความจริง ; ไลบรารี jQuery จริง ๆ แล้วมีวิธีการภายใน (ซึ่งไม่มีเอกสารและในทางทฤษฎีสามารถเปลี่ยนแปลงได้ตลอดเวลา) เรียกว่าcleanData() (นี่คือสิ่งที่วิธีนี้ดูเหมือน ) ซึ่งจะล้างข้อมูล / เหตุการณ์ทั้งหมดที่เกี่ยวข้องกับองค์ประกอบโดยอัตโนมัติเมื่อลบออกจาก DOM (ไม่ว่าจะผ่านทางนี้. remove(), empty(), html("")ฯลฯ )


เบราว์เซอร์รุ่นเก่า

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

หากคุณต้องการคำอธิบายเชิงลึกเพิ่มเติมเกี่ยวกับสาเหตุรูปแบบและโซลูชันที่ใช้เพื่อแก้ไขการรั่วไหลของหน่วยความจำรุ่น IE ดั้งเดิมฉันขอแนะนำให้คุณอ่านบทความ MSDN นี้เกี่ยวกับการทำความเข้าใจและแก้ไขรูปแบบการรั่วไหลของ Internet Explorer

อีกบทความที่เกี่ยวข้องกับเรื่องนี้:

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


22
ตาม jquery Documentation เมื่อใช้เมธอด remove () บนองค์ประกอบผู้ฟังเหตุการณ์ทั้งหมดจะถูกลบออกจากหน่วยความจำ สิ่งนี้มีผลต่อองค์ประกอบที่มัน selft และโหนดลูกทั้งหมด หากคุณต้องการเก็บผู้ฟังเหตุการณ์ไว้ในหน่วยความจำคุณควรใช้. delach () แทน มีประโยชน์เมื่อองค์ประกอบที่ลบออกจะถูกแทรกอีกครั้งบนโดม
Lothre1

1
หากองค์ประกอบมีองค์ประกอบย่อยของเด็กองค์ประกอบนั้นจะแยกผู้ฟังเหตุการณ์ในองค์ประกอบย่อยด้วยหรือไม่
CBeTJlu4ok

1
@ Lothre1 - นั่นคือเฉพาะเมื่อใช้removeวิธีการ ส่วนใหญ่ DOM จะเพิ่งถูกลบทิ้งอย่างสมบูรณ์ (เช่นลิงค์เทอร์โบหรือบางอย่าง) ฉันสงสัยว่าหน่วยความจำจะได้รับผลกระทบอย่างไรถ้าฉันdocument.body.innerHTML = ''...
vsync

1
ฉันต้องการมากกว่า "ประสบการณ์ส่วนตัว" เช่นเดียวกับข้อมูลและการทดสอบและลิงก์ไปยังข้อมูลจำเพาะที่บอกว่าหน่วยความจำยังคงอยู่บนโหนดที่ไม่อยู่ในเอกสารอีกต่อไปสิ่งนี้สำคัญเกินกว่าที่จะเชื่อใจคำพูดของใครบางคนโดยไม่มีข้อพิสูจน์ :)
vsync

1
@ Lothre1 ขอบคุณ - ฉันขุดลึกลงไปเล็กน้อยและพบว่า jQuery ทำหน้าที่แตกต่างจาก JavaScript ปกติในแง่นี้อย่างไร ได้อัปเดตคำตอบ
dsgriffin

23

เกี่ยวกับ jQuery:

. Remove () วิธีการใช้องค์ประกอบออกจาก DOM ใช้. Remove () เมื่อคุณต้องการลบองค์ประกอบเองรวมถึงทุกสิ่งที่อยู่ภายใน นอกเหนือจากองค์ประกอบเองเหตุการณ์ที่ถูกผูกไว้ทั้งหมดและข้อมูล jQuery ที่เกี่ยวข้องกับองค์ประกอบจะถูกลบออก หากต้องการลบองค์ประกอบโดยไม่ลบข้อมูลและเหตุการณ์ให้ใช้. debet () แทน

การอ้างอิง: http://api.jquery.com/remove/

jQuery v1.8.2 .remove()รหัสที่มา:

remove: function( selector, keepData ) {
    var elem,
        i = 0;

    for ( ; (elem = this[i]) != null; i++ ) {
        if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
            if ( !keepData && elem.nodeType === 1 ) {
                jQuery.cleanData( elem.getElementsByTagName("*") );
                jQuery.cleanData( [ elem ] );
            }

            if ( elem.parentNode ) {
                elem.parentNode.removeChild( elem );
            }
        }
    }

    return this;
}

เห็นได้ชัดว่า jQuery ใช้ node.removeChild()

ตามนี้: https://developer.mozilla.org/en-US/docs/DOM/Node.removeChild ,

The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.

เช่นผู้ฟังเหตุการณ์อาจถูกลบ แต่nodeยังคงอยู่ในหน่วยความจำ


3
คุณแค่เพิ่มความสับสน - jQuery ไม่ได้ทำอะไรกับตัวจัดการที่removeChildไม่ง่าย ทั้งสองยังส่งคืนการอ้างอิงที่คุณอาจเก็บไว้ติดตั้งใหม่ (ซึ่งในกรณีนี้มันจะยังคงอยู่ในหน่วยความจำ) หรือวิธีการขว้างปา
Oleg V. Volkov

ฉันรู้: D. แล้วคุณเป็นใครที่แก้ไขคำถาม เพราะฉันสาบานได้ว่ามีบางอย่างเกี่ยวกับการใช้ jQuery เพื่อลบองค์ประกอบ DOM ในคำถามก่อนหน้านี้ ตอนนี้คำตอบของฉันดูเหมือนว่าฉันกำลังอธิบายสิ่งต่าง ๆ เพียงจังหวะของอัตตาของฉัน เฮ้คุณสามารถลงคะแนนได้ตลอดเวลา
Sreenath S

8

อย่าลังเลที่จะดูฮีปเพื่อดูการรั่วไหลของหน่วยความจำในตัวจัดการเหตุการณ์ที่อ้างอิงถึงองค์ประกอบด้วยการปิดและองค์ประกอบที่อ้างอิงถึงตัวจัดการเหตุการณ์

ตัวรวบรวมขยะไม่ชอบการอ้างอิงแบบวงกลม

กรณีการรั่วไหลของหน่วยความจำปกติ: ยอมรับว่าวัตถุมีการอ้างอิงถึงองค์ประกอบ องค์ประกอบนั้นมีการอ้างอิงถึงตัวจัดการ และตัวจัดการมีการอ้างอิงไปยังวัตถุ วัตถุนั้นอ้างอิงวัตถุอื่นจำนวนมาก วัตถุนี้เป็นส่วนหนึ่งของคอลเลกชันที่คุณคิดว่าคุณทิ้งไปโดยไม่อ้างถึงจากคอลเลกชันของคุณ => วัตถุทั้งหมดและทั้งหมดที่อ้างถึงจะยังคงอยู่ในหน่วยความจำจนกระทั่งออกจากหน้า => คุณต้องคิดถึงวิธีการฆ่าแบบสมบูรณ์สำหรับคลาสอ็อบเจ็กต์ของคุณหรือเชื่อถือเฟรมเวิร์ก mvc

ยิ่งกว่านั้นอย่าลังเลที่จะใช้ส่วนรักษาต้นไม้ของเครื่องมือพัฒนา Chrome


8

เพียงขยายคำตอบอื่น ๆ ...

ตัวจัดการเหตุการณ์ที่ได้รับมอบหมายจะไม่ถูกลบออกเมื่อมีการลบองค์ประกอบ

$('body').on('click', '#someEl', function (event){
  console.log(event);
});

$('#someEL').remove(); // removing the element from DOM

ตรวจสอบตอนนี้:

$._data(document.body, 'events');

9
ตัวจัดการเหตุการณ์แนบมากับร่างกายไม่ใช่ #someEl โดยธรรมชาติแล้วตัวจัดการไม่ควรลบออกตราบใดที่ร่างกายยังอยู่ที่นี่
Yangshun Tay

สามารถลบได้ด้วยตนเอง: stackoverflow.com/questions/22400907/…
fangxing

7

เกี่ยวกับjQueryวิธีการทั่วไปต่อไปนี้จะลบการสร้างอื่น ๆ เช่นตัวจัดการข้อมูลและเหตุการณ์:

ลบ ()

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

ว่าง ()

เพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำ jQuery จะลบการสร้างอื่น ๆ เช่นข้อมูลและตัวจัดการเหตุการณ์จากองค์ประกอบลูกก่อนที่จะลบองค์ประกอบเอง

HTML ()

นอกจากนี้ jQuery จะลบการสร้างอื่น ๆ เช่นข้อมูลและตัวจัดการเหตุการณ์จากองค์ประกอบลูกก่อนที่จะแทนที่องค์ประกอบเหล่านั้นด้วยเนื้อหาใหม่


2

ใช่ตัวเก็บขยะจะลบออกเช่นกัน อาจไม่เป็นเช่นนั้นกับเบราว์เซอร์รุ่นเก่าเสมอไป


7
ข้อความสั่งของคุณควรได้รับการสนับสนุนโดยเอกสาร API ตัวอย่างและอื่น ๆ
Paolo Fulgoni
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.