Apa Cara yang Tepat untuk Menghancurkan Contoh Peta?

89

Saya baru-baru ini mengembangkan aplikasi seluler html5. Aplikasi tersebut adalah satu halaman tempat peristiwa perubahan hash navigasi menggantikan seluruh DOM. Salah satu bagian dari aplikasinya adalah Google Map menggunakan API v3. Sebelum div peta dihapus dari DOM, saya ingin menghapus event handler / listener dan mengosongkan memori sebanyak mungkin karena pengguna tidak dapat kembali ke bagian itu lagi.

Apa cara terbaik untuk menghancurkan instance peta?

Chad Killingsworth
sumber
Pertanyaan terkait (2014): stackoverflow.com/questions/21142483/…
kashiraja
Kode untuk mencoba menghapus semua pendengar acara di peta, bug Google maps 35821412
kashiraja

Jawaban:

48

Saya menambahkan jawaban kedua atas pertanyaan ini, karena saya tidak ingin menghapus bolak-balik yang kami miliki melalui komentar tindak lanjut pada jawaban saya sebelumnya.

Namun baru-baru ini saya menemukan beberapa informasi yang secara langsung menjawab pertanyaan Anda, jadi saya ingin berbagi. Saya tidak tahu apakah Anda menyadarinya, tetapi selama Video Jam Kerja Google Maps API 9 Mei 2012 , Chris Broadfoot dan Luke Mahe dari Google membahas pertanyaan ini dari stackoverflow. Jika Anda menyetel pemutaran video ke 12:50, itu adalah bagian di mana mereka membahas pertanyaan Anda.

Pada dasarnya, mereka mengakui bahwa itu adalah bug, tetapi juga menambahkan bahwa mereka tidak benar-benar mendukung kasus penggunaan yang melibatkan pembuatan / penghancuran contoh peta yang berurutan. Mereka sangat menyarankan untuk membuat satu contoh peta dan menggunakannya kembali dalam skenario apa pun seperti ini. Mereka juga berbicara tentang menyetel peta ke null, dan secara eksplisit menghapus event listener. Anda mengungkapkan kekhawatiran tentang pendengar acara, saya pikir hanya menyetel peta ke nol saja sudah cukup, tetapi tampaknya kekhawatiran Anda valid, karena mereka menyebutkan pendengar acara secara khusus. Mereka juga merekomendasikan untuk menghapus DIV yang menahan peta juga.

Bagaimanapun, hanya ingin meneruskan ini dan memastikan itu termasuk dalam diskusi stackoverflow dan berharap ini membantu Anda dan orang lain-

Sean Mickey
sumber
2
Terima kasih - Saya meminta mereka untuk menjawab pertanyaan tersebut pada jam kerja tetapi belum sempat untuk memeriksa videonya.
Chad Killingsworth
Anda dapat dengan mudah memperbarui jawaban sebelumnya yang menyebutkan bahwa ini adalah pembaruan ...
TJ
4
Luar biasa .. ini tahun 2018 dan sepertinya masih belum ada cara untuk melakukan ini.
JP Silvashy
28

The jawaban resmi adalah Anda tidak. Contoh peta dalam aplikasi satu halaman harus digunakan kembali dan tidak dihancurkan lalu dibuat ulang.

Untuk beberapa aplikasi halaman tunggal, ini mungkin berarti merancang ulang solusi sedemikian rupa sehingga setelah peta dibuat, peta tersebut mungkin tersembunyi atau terputus dari DOM, tetapi tidak pernah dimusnahkan / dibuat ulang.

Chad Killingsworth
sumber
Ini sangat buruk - Saya memiliki aplikasi satu halaman multibahasa dan saya ingin menampilkan Google Map pada bahasa yang dipilih.
artuska
14

Karena tampaknya Anda tidak dapat benar-benar menghancurkan contoh peta, cara untuk mengurangi masalah ini jika

  • Anda perlu menampilkan beberapa peta sekaligus di situs web
  • jumlah peta dapat berubah dengan interaksi pengguna
  • peta perlu disembunyikan dan ditampilkan kembali bersama dengan komponen lain (yaitu mereka tidak muncul dalam posisi tetap di DOM)

menyimpan sekumpulan contoh peta. Pool terus melacak instance yang digunakan, dan ketika diminta instance baru, ia memeriksa apakah ada instance peta yang tersedia gratis: jika ada, itu akan mengembalikan yang sudah ada, jika tidak, itu akan membuat contoh peta baru dan mengembalikannya, menambahkannya ke kolam. Dengan cara ini Anda hanya akan memiliki jumlah maksimum contoh yang sama dengan jumlah maksimum peta yang pernah Anda tampilkan secara bersamaan di layar. Saya menggunakan kode ini (membutuhkan 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
    }
 }
}

Anda meneruskan opsi peta awal (sesuai argumen kedua dari konstruktor google.maps.Map), dan mengembalikan instance peta (tempat Anda dapat memanggil fungsi yang berkaitan dengan google.maps.Map), dan container, yang mana Anda dapat mengatur gaya menggunakan kelas "myDivClassHereForStyling", dan Anda dapat menambahkan DOM secara dinamis. Jika Anda perlu mengatur ulang sistem, Anda dapat menggunakan mapInstancesPool.reset (). Ini akan mengatur ulang penghitung ke 0, sambil menyimpan semua contoh yang ada di kumpulan untuk digunakan kembali. Dalam aplikasi saya, saya perlu menghapus semua peta sekaligus dan membuat satu set peta baru, jadi tidak ada fungsi untuk mendaur ulang contoh peta tertentu: jarak tempuh Anda mungkin berbeda. Untuk menghapus peta dari layar, saya menggunakan detach jQuery, yang tidak merusak container peta.

Dengan menggunakan sistem ini, dan menggunakan

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

dan berlari

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

(di mana divReference adalah objek jQuery div yang dikembalikan dari Instance Pool) pada setiap div yang saya hapus, saya berhasil menjaga penggunaan memori Chrome lebih atau kurang stabil, berlawanan dengan peningkatan setiap kali saya menghapus peta dan menambahkan yang baru.

Paolo Mioni
sumber
ANDA TELAH MENYELAMATKAN HIDUP SAYA! Thnks;)
Felipe Desiderati
Senang bisa membantu !!
Paolo Mioni
5

Saya akan menyarankan untuk menghapus konten div peta dan menggunakan deletevariabel yang memegang referensi ke peta, dan mungkin secara eksplisitdelete menggunakan event listener.

Namun, ada bug yang diketahui , dan ini mungkin tidak berfungsi.

Andrew Leach
sumber
Ini adalah diskusi yang bagus. Saya tidak berpikir menelepon deletemenambah banyak (lihat stackoverflow.com/q/742623/1314132 ), tetapi itu benar-benar tidak ada salahnya. Pada akhirnya, pertanyaannya adalah: apakah ada referensi ke objek tersebut? Jika ya, sampah tidak akan dikumpulkan.
Sean Mickey
1
@SeanMickey: dimana bug menjadi relevan. Versi 2 harus GUnload()menghapus semua referensi internal API.
Andrew Leach
Saya telah menguji dengan halaman ini di Chrome: people.missouristate.edu/chadkillingsworth/mapsexamples/… Sejauh ini penggunaan memori setelah peta dihapus hanya turun sedikit, tetapi jauh dari level sebelum peta dibuat.
Chad Killingsworth
@Andonesia Tetapi jika mereka memiliki bug yang menyebabkan kebocoran memori, tidak banyak yang dapat kami lakukan hingga diperbaiki. Maksud saya, jika membuat semua objek peta tidak dapat dijangkau tidak berfungsi, maka deleteitu bukanlah perbaikan. Mereka harus memperbaiki besarnya sehingga membuat referensi tidak dapat dijangkau berfungsi sebagaimana mestinya atau menambahkan fungsi baru yang menyediakan fungsionalitas yang Anda jelaskan GUnload().
Sean Mickey
1
Chad / Andrew: ya, saya telah mereproduksi masalah ini, sayangnya deletedan innerHTMLmenghapus memori tidak sepenuhnya menghapus. Sayangnya ini bukan bug dengan prioritas tinggi.
Chris Broadfoot
2

Karena google tidak menyediakan gunload () untuk api v3 lebih baik gunakan iframe di html dan tetapkan map.html sebagai sumber untuk iframe ini. setelah digunakan jadikan src sebagai null. Itu pasti akan membebaskan memori yang dikonsumsi oleh peta.

kumar
sumber
2
Setiap instance dari iframe kemudian harus memuat ulang api peta yang tidak ideal.
Chad Killingsworth
1

Saat Anda menghapus div, itu menghilangkan panel tampilan dan peta akan menghilang. Untuk menghapus instance peta, cukup pastikan bahwa referensi Anda ke peta disetel ke nulldan semua referensi ke bagian lain dari peta disetel ke null. Pada titik itu, pengumpulan sampah JavaScript akan melakukan pembersihan, seperti yang dijelaskan di: Bagaimana cara kerja pengumpulan sampah di JavaScript? .

Sean Mickey
sumber
1
Saya tidak yakin bahwa menyetel variabel peta ke null akan menghapus semua event listener dengan benar.
Chad Killingsworth
1
Bukan hanya peta yang harus diatur null, tetapi referensi ke hal lain. Jadi, jika referensi marker disetel ke null, sehingga tidak dapat dijangkau , tidak ada cara untuk menjangkau pemroses peristiwa. Ini mungkin masih terhubung ke peta, tetapi peta tidak dapat dijangkau, jadi itu hanya sebongkah besar memori yang pada dasarnya menjadi yatim piatu. Ini sama dengan mengatur Array.length = 0; Jika tidak ada referensi lain untuk anggota, mereka hanya membentuk kelompok memori yatim piatu yang memenuhi syarat untuk pengumpulan sampah.
Sean Mickey
0

Saya kira yang Anda bicarakan addEventListener. Saat Anda menghapus elemen DOM, beberapa browser membocorkan peristiwa ini dan tidak menghapusnya. Inilah mengapa jQuery melakukan beberapa hal saat menghapus sebuah elemen:

  • Ini menghapus acara saat bisa digunakan removeEventListener. Itu berarti mempertahankan array dengan event listener yang ditambahkannya ke elemen ini.
  • Ini menghapus atribut tentang peristiwa ( onclick,, onblurdll) yang digunakan deletepada elemen DOM ketika addEventListenertidak tersedia (masih, ia memiliki larik tempat menyimpan peristiwa yang ditambahkan).
  • Ini mengatur elemen nulluntuk menghindari kebocoran memori IE 6/7/8.
  • Ini kemudian menghapus elemen.
Florian Margaine
sumber
Saya terutama mengacu pada peristiwa Google Maps API internal. Mereka dapat ditambahkan / dihapus / dipicu menggunakan metode kejadian API yang didokumentasikan di developers.google.com/maps/documentation/javascript/… . Meskipun fungsinya mirip dengan addEventListener browser, ada sejumlah besar peristiwa khusus khusus untuk peta (seperti "bounds_changed" dan beberapa penangan peristiwa tersebut menghubungkan ke peristiwa browser seperti peristiwa "ubah ukuran" peta.
Chad Killingsworth
Kemudian pertahankan serangkaian peristiwa yang ditambahkan dan hapus lalu gunakan secara manual removeEventListeneratau deletebergantung pada jenis peristiwa.
Florian Margaine