วิธีที่เหมาะสมในการทำลายอินสแตนซ์แผนที่คืออะไร?


92

ฉันเพิ่งพัฒนาแอปพลิเคชันมือถือ html5 แอปพลิเคชันเป็นหน้าเดียวที่เหตุการณ์การเปลี่ยนแปลงแฮชการนำทางแทนที่ DOM ทั้งหมด ส่วนหนึ่งของแอปพลิเคชันคือ Google Map โดยใช้ API v3 ก่อนที่ div แผนที่จะถูกลบออกจาก DOM ฉันต้องการลบตัวจัดการเหตุการณ์ / ตัวฟังใด ๆ และเพิ่มหน่วยความจำให้มากที่สุดเท่าที่จะเป็นไปได้เนื่องจากผู้ใช้จะไม่กลับไปที่ส่วนนั้นอีก

วิธีที่ดีที่สุดในการทำลายอินสแตนซ์แผนที่คืออะไร?


คำถามที่เกี่ยวข้อง (2014): stackoverflow.com/questions/21142483/…
kashiraja

รหัสสำหรับการพยายามลบผู้ฟังเหตุการณ์ทั้งหมดบนแผนที่ข้อผิดพลาดของ Google Maps 35821412
kashiraja

คำตอบ:


49

ฉันกำลังเพิ่มคำตอบที่สองสำหรับคำถามนี้เนื่องจากฉันไม่ต้องการลบคำตอบกลับไปกลับมาที่เรามีผ่านความคิดเห็นติดตามผลของคำตอบก่อนหน้านี้

แต่เมื่อเร็ว ๆ นี้ฉันได้พบข้อมูลบางอย่างที่ตรงกับคำถามของคุณและฉันจึงอยากแบ่งปัน ฉันไม่รู้ว่าคุณรับรู้เรื่องนี้หรือไม่ แต่ในวิดีโอGoogle Maps API Office Hours เมื่อวันที่ 9 พฤษภาคม 2555 Chris Broadfoot และ Luke Mahe จาก Google ได้พูดคุยเกี่ยวกับคำถามนี้จาก stackoverflow หากคุณตั้งค่าการเล่นวิดีโอเป็น 12:50 นั่นคือส่วนที่พวกเขาพูดถึงคำถามของคุณ

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

ไม่ว่าในกรณีใดเพียงแค่ต้องการส่งต่อสิ่งนี้และตรวจสอบให้แน่ใจว่ารวมอยู่ในการอภิปราย stackoverflow และหวังว่ามันจะช่วยคุณและคนอื่น ๆ -


2
ขอบคุณ - ฉันขอให้พวกเขาจัดการคำถามในเวลาทำการ แต่ยังไม่มีโอกาสตรวจสอบวิดีโอ
Chad Killingsworth

คุณสามารถอัปเดตคำตอบก่อนหน้านี้ได้โดยระบุว่าเป็นการอัปเดต ...
TJ

4
ยอดเยี่ยมมาก .. มันเป็นปี 2018 และดูเหมือนจะไม่มีทางทำเช่นนี้
JP Silvashy

28

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

สำหรับแอปพลิเคชันหน้าเดียวบางตัวอาจหมายถึงการออกแบบโซลูชันใหม่เช่นเมื่อสร้างแผนที่แล้วแผนที่อาจถูกซ่อนหรือตัดการเชื่อมต่อจาก DOM แต่จะไม่ถูกทำลาย / สร้างขึ้นใหม่


นี่แย่มาก - ฉันมีแอปพลิเคชั่นหน้าเดียวหลายภาษาและฉันต้องการแสดง Google Map ในภาษาที่เลือก
artuska

ดูเหมือนว่าสิ่งนี้ได้รับการแก้ไขแล้วในเวอร์ชัน 3.38.1 (แม้ว่าฉันจะไม่ได้ตรวจสอบโดยอิสระ)
Chrest

15

เนื่องจากเห็นได้ชัดว่าคุณไม่สามารถทำลายอินสแตนซ์แผนที่ได้จริงวิธีลดปัญหานี้หาก

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

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

var mapInstancesPool = {
 pool: [],
 used: 0,
 getInstance: function(options){
    if(mapInstancesPool.used >= mapInstancesPool.pool.length){
        mapInstancesPool.used++;
        mapInstancesPool.pool.push (mapInstancesPool.createNewInstance(options));
    } else { 
        mapInstancesPool.used++;
    }
    return mapInstancesPool.pool[mapInstancesPool.used-1];
 },
 reset: function(){
    mapInstancesPool.used = 0;
 },
 createNewInstance: function(options){
    var div = $("<div></div>").addClass("myDivClassHereForStyling");
    var map =   new google.maps.Map(div[0], options);
    return {
        map: map,
        div: div
    }
 }
}

คุณส่งผ่านตัวเลือกแผนที่เริ่มต้น (ตามอาร์กิวเมนต์ที่สองของตัวสร้างของ google.maps.Map) และส่งคืนทั้งอินสแตนซ์แผนที่ (ซึ่งคุณสามารถเรียกใช้ฟังก์ชันที่เกี่ยวข้องกับ google.maps.Map) และคอนเทนเนอร์ซึ่ง คุณสามารถจัดรูปแบบโดยใช้คลาส "myDivClassHereForStyling" และคุณสามารถต่อท้าย DOM แบบ dinamically หากคุณต้องการรีเซ็ตระบบคุณสามารถใช้ mapInstancesPool.reset () มันจะรีเซ็ตตัวนับเป็น 0 ในขณะที่เก็บอินสแตนซ์ที่มีอยู่ทั้งหมดไว้ในพูลเพื่อใช้ซ้ำ ในแอปพลิเคชันของฉันฉันจำเป็นต้องลบแผนที่ทั้งหมดพร้อมกันและสร้างชุดแผนที่ใหม่ดังนั้นจึงไม่มีฟังก์ชันในการรีไซเคิลอินสแตนซ์แผนที่ที่เฉพาะเจาะจง: ระยะทางของคุณอาจแตกต่างกันไป ในการลบแผนที่ออกจากหน้าจอฉันใช้การปลดของ jQuery ซึ่งไม่ทำลายคอนเทนเนอร์ของแผนที่

โดยใช้ระบบนี้และใช้

google.maps.event.clearInstanceListeners(window);
google.maps.event.clearInstanceListeners(document);

และทำงาน

google.maps.event.clearInstanceListeners(divReference[0]);
divReference.detach()

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


คุณได้ช่วยชีวิตฉันแล้ว! Thnks;)
Felipe Desiderati

ดีใจที่ได้รับความช่วยเหลือ !!
Paolo Mioni

5

ฉันอยากจะแนะนำให้ลบเนื้อหาของแผนที่ div และใช้deleteกับตัวแปรที่ถือการอ้างอิงไปยังแผนที่และอาจทำให้deleteผู้ฟังเหตุการณ์ใด ๆอย่างชัดเจน

มีข้อบกพร่องที่ได้รับการยอมรับและอาจไม่ได้ผล


นี่เป็นการอภิปรายที่ดี ฉันไม่คิดว่าการโทรdeleteจะเพิ่มอะไรมาก (ดูstackoverflow.com/q/742623/1314132 ) แต่มันไม่เจ็บเลยจริงๆ ในท้ายที่สุดคำถามนี้มีการอ้างอิงถึงวัตถุหรือไม่? ถ้าใช่จะไม่เก็บขยะ
Sean Mickey

1
@SeanMickey: จุดบกพร่องที่เกี่ยวข้อง เวอร์ชัน 2 GUnload()ต้องลบการอ้างอิงภายในของ API ทั้งหมด
Andrew Leach

ฉันได้ทำการทดสอบกับหน้านี้ใน Chrome: people.missouristate.edu/chadkillingsworth/mapsexamples/…จนถึงขณะนี้การใช้งานหน่วยความจำหลังจากที่แผนที่ถูกลบออกจะลดลงเพียงเล็กน้อย แต่ไม่มีที่ไหนเลยที่ใกล้ระดับก่อนที่แผนที่จะถูกสร้างอินสแตนซ์
Chad Killingsworth

@AndrewLeach แน่นอน. แต่ถ้าพวกเขามีจุดบกพร่องที่ทำให้หน่วยความจำรั่วก็ไม่มีอะไรที่เราสามารถทำได้จนกว่าจะได้รับการแก้ไข ฉันหมายความว่าถ้าการทำให้วัตถุบนแผนที่ทั้งหมดไม่สามารถเข้าถึงได้ไม่ได้ผลก็deleteไม่ใช่วิธีแก้ไข GUnload()พวกเขามีการแก้ไขเพื่อให้ขนาดใหญ่ที่ทำให้การอ้างอิงผลงานที่ไม่สามารถเข้าถึงได้ตามที่ควรหรือเพิ่มฟังก์ชั่นใหม่ที่ให้ฟังก์ชั่นที่คุณอธิบายสำหรับ
Sean Mickey

1
แชด / แอนดรูว์: ใช่ฉันได้สร้างปัญหานี้ซ้ำขออภัยdeleteและการinnerHTMLล้างหน่วยความจำที่ไม่สมบูรณ์ น่าเสียดายที่ไม่ใช่บั๊กที่มีลำดับความสำคัญสูง
Chris Broadfoot

2

เนื่องจาก Google ไม่ได้ให้ gunload () สำหรับ api v3 จึงควรใช้ iframe ใน html และกำหนด map.html เป็นแหล่งที่มาของ iframe นี้ หลังการใช้งานให้ src เป็น null นั่นจะทำให้หน่วยความจำที่ใช้โดยแผนที่เป็นอิสระอย่างแน่นอน


2
จากนั้นแต่ละอินสแตนซ์ของ iframe จะต้องโหลด API แผนที่ซ้ำซึ่งไม่เหมาะ
Chad Killingsworth

1

เมื่อคุณลบdivนั่นจะเป็นการลบแผงแสดงผลและแผนที่จะหายไป ในการลบเช่นแผนที่เพียงให้แน่ใจว่าการอ้างอิงของคุณลงในแผนที่มีการตั้งค่าnullและการอ้างอิงใด ๆ กับส่วนอื่น ๆ nullของแผนที่มีการกำหนดให้ เมื่อถึงจุดนั้นการรวบรวมขยะ JavaScript จะดูแลการทำความสะอาดดังที่อธิบายไว้ใน: การรวบรวมขยะทำงานอย่างไรใน JavaScript .


1
ฉันไม่แน่ใจว่าการตั้งค่าตัวแปรแผนที่เป็น null จะลบตัวฟังเหตุการณ์ทั้งหมดได้อย่างถูกต้อง
Chad Killingsworth

1
ไม่ใช่แค่แผนที่ที่ต้องตั้งค่าnullแต่ต้องอ้างอิงถึงสิ่งอื่นใด ดังนั้นหากตั้งค่าการอ้างอิงเครื่องหมายเป็นnullทำให้ไม่สามารถเข้าถึงได้จะไม่มีทางเข้าถึงผู้ฟังเหตุการณ์ได้ มันอาจจะยังคงเชื่อมต่อกับแผนที่ แต่ไม่สามารถเข้าถึงแผนที่ได้ดังนั้นมันจึงเป็นเพียงหน่วยความจำก้อนโตที่กลายเป็นเด็กกำพร้าไปแล้ว เหมือนกับการตั้งค่าArray.length = 0; หากไม่มีการอ้างอิงอื่น ๆ ถึงสมาชิกพวกเขาจะสร้างกลุ่มของหน่วยความจำที่ไม่มีเจ้าของที่มีสิทธิ์สำหรับการรวบรวมขยะ
Sean Mickey

0

addEventListenerผมคิดว่าคุณกำลังพูดถึง เมื่อคุณลบองค์ประกอบ DOM เบราว์เซอร์บางตัวจะรั่วไหลเหตุการณ์เหล่านี้และไม่ได้ลบออก นี่คือสาเหตุที่ jQuery ทำหลายสิ่งเมื่อลบองค์ประกอบ:

  • จะลบเหตุการณ์เมื่อสามารถใช้งานremoveEventListenerได้ นั่นหมายความว่าจะเก็บอาร์เรย์ไว้กับตัวฟังเหตุการณ์ที่เพิ่มในองค์ประกอบนี้
  • มันลบแอตทริบิวต์เกี่ยวกับเหตุการณ์ (คนonclick, onblurฯลฯ ) ใช้deleteในองค์ประกอบ DOM เมื่อaddEventListenerไม่สามารถใช้ได้ (ยังคงก็มีอาร์เรย์ที่จะเก็บเหตุการณ์เพิ่ม)
  • มันตั้งค่าองค์ประกอบnullเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำ IE 6/7/8
  • จากนั้นจะลบองค์ประกอบ

ฉันหมายถึงเหตุการณ์ภายใน Google Maps API เป็นหลัก พวกเขาสามารถเพิ่ม / ลบออก / เรียกใช้วิธีการจัดกิจกรรม API เอกสารที่developers.google.com/maps/documentation/javascript/... แม้ว่าจะมีฟังก์ชันการทำงานคล้ายกับเบราว์เซอร์ addEventListener แต่ก็มีเหตุการณ์ที่กำหนดเองเฉพาะสำหรับแผนที่จำนวนมาก (เช่น "bounds_changed" และตัวจัดการเหตุการณ์บางส่วนจะเชื่อมโยงกับเหตุการณ์ของเบราว์เซอร์เช่นเหตุการณ์ "ปรับขนาด" แผนที่
Chad Killingsworth

จากนั้นเก็บอาร์เรย์ของเหตุการณ์ที่เพิ่มและลบออกด้วยตนเองโดยใช้removeEventListenerหรือdeleteขึ้นอยู่กับชนิดของเหตุการณ์
Florian Margaine
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.