マップインスタンスを破棄する適切な方法は何ですか?


89

最近、html5モバイルアプリケーションを開発しました。アプリケーションは、ナビゲーションハッシュ変更イベントがDOM全体を置き換えた単一のページでした。アプリケーションの1つのセクションは、APIv3を使用したGoogleマップでした。map divがDOMから削除される前に、イベントハンドラー/リスナーを削除し、ユーザーがそのセクションに再び戻らないように、できるだけ多くのメモリを解放したいと思います。

マップインスタンスを破棄する最良の方法は何ですか?



マップ上のすべてのイベントリスナーを削除しようとするためのコードは、Googleがバグにマッピング35821412
kashiraja

回答:


48

以前の回答に対するフォローアップコメントを介して行った前後を削除したくないので、この質問に2番目の回答を追加します。

しかし、最近、あなたの質問に直接対処するいくつかの情報に出くわしたので、共有したいと思いました。これをご存知かどうかはわかりませんが、2012年5月9日のGoogle Maps APIオフィスアワーのビデオで、GoogleのChrisBroadfootとLukeMaheがstackoverflowからのこの質問について話し合いました。ビデオ再生を12:50に設定すると、それは彼らがあなたの質問について話し合うセクションです。

基本的に、彼らはそれがバグであることを認めていますが、連続するマップインスタンスの作成/破棄を伴うユースケースを実際にはサポートしていないとも付け加えています。マップの単一のインスタンスを作成し、この種のシナリオでそれを再利用することを強くお勧めします。また、マップをnullに設定し、イベントリスナーを明示的に削除する方法についても説明します。イベントリスナーについて懸念を表明されました。マップをnullに設定するだけで十分だと思いましたが、イベントリスナーについて具体的に言及しているため、懸念は妥当であるように見えます。また、マップを保持しているDIVも完全に削除することを推奨しました。

とにかく、これを伝えて、stackoverflowのディスカッションに含まれていることを確認し、あなたや他の人に役立つことを願っています-


2
ありがとう-私は彼らに営業時間に質問に取り組むように頼んだが、まだビデオをチェックする機会を得ていなかった。
チャドキリングスワース2012年

さて、あなたはそれが更新であると述べて前の答えを単に更新することができたでしょう...
TJ

4
素晴らしい.. 2018年ですが、これを行う方法はまだないようです。
JP Silvashy 2018年

28

公式の答えはあなたがいないです。シングルページアプリケーションのマップインスタンスは再利用する必要があり、破棄してから再作成しないでください。

一部のシングルページアプリケーションの場合、これは、マップが作成されると非表示になるか、DOMから切断されるようにソリューションを再構築することを意味する場合がありますが、マップが破棄/再作成されることはありません。


これは非常に悪いことです—私は多言語のシングルページアプリケーションを持っていて、選択した言語でGoogleマップを表示したいと思っています。
artuska 2018年

14

どうやらマップインスタンスを実際に破壊することはできないので、この問題を軽減する方法は

  • ウェブサイトに一度に複数の地図を表示する必要があります
  • マップの数は、ユーザーの操作によって変わる可能性があります
  • マップは非表示にして、他のコンポーネントと一緒に再表示する必要があります(つまり、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のコンストラクターの2番目の引数に従って)開始マップオプションを渡すと、マップインスタンス(google.maps.Mapに関連する関数を呼び出すことができる)とコンテナーの両方が返されます。クラス「myDivClassHereForStyling」を使用してスタイルを設定したり、DOMに動的に追加したりできます。システムをリセットする必要がある場合は、mapInstancesPool.reset()を使用できます。プール内の既存のすべてのインスタンスを再利用できるように保持しながら、カウンターを0にリセットします。私のアプリケーションでは、すべてのマップを一度に削除して新しいマップセットを作成する必要があったため、特定のマップインスタンスをリサイクルする機能はありません。マイレージは異なる場合があります。画面からマップを削除するには、jQueryのデタッチを使用します。これはマップのコンテナを破壊しません。

このシステムを使用して、

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

と実行中

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

(divReferenceはインスタンスプールから返されるdivのjQueryオブジェクトです)削除するすべてのdivで、マップを削除して新しいマップを追加するたびに増加するのではなく、Chromeのメモリ使用量をほぼ安定させることができました。


あなたは私の命を救った!Thnks;)
Felipe Desiderati

お役に立ててうれしいです!
Paolo Mioni

5

map divのコンテンツを削除deleteし、マップへの参照を保持する変数で使用し、おそらくdeleteイベントリスナーを明示的に使用することをお勧めします。

あり定評バグはかかわらず、これは動作しない場合があります。


これは良い議論です。私は呼び出しdeleteが多くを追加するとは思わないが(stackoverflow.com/q/742623/1314132を参照)、それは本当に害はありません。結局、それはこの質問に帰着します:オブジェクトへの参照はありますか?はいの場合、ガベージコレクションは行われません。
ショーンミッキー

1
@SeanMickey:バグが関連する場所です。バージョン2ではGUnload()、APIの内部参照をすべて削除する必要があります。
アンドリューリーチ2012年

Chromeでこのページをテストしてきました:people.missouristate.edu/chadkillingsworth/mapsexamples/…これまでのところ、マップが削除された後のメモリ使用量はわずかに低下しますが、マップがインスタンス化される前のレベルにはほど遠いです。
チャドキリングスワース2012年

@AndrewLeach絶対に。ただし、メモリリークの原因となるバグがある場合は、修正されるまでできることはほとんどありません。つまり、すべてのマップオブジェクトを到達不能にすることが機能しない場合、それdeleteは実際には修正されません。参照に到達できないようにすることで正常に機能するように大きな問題を修正するか、説明した機能を提供する新しい関数を追加する必要がありますGUnload()
ショーンミッキー

1
チャド/アンドリュー:ええ、私はこの問題を再現しましたが、残念ながらdelete、クリアしinnerHTMLてもメモリは完全にはクリアされません。残念ながら、これは優先度の高いバグではありません。
クリスブロードフット2012年

2

グーグルはapiv3にgunload()を提供していないので、htmlでiframeを使用し、このiframeのソースとしてmap.htmlを割り当てる方がよいでしょう。使用後、srcをnullにします。それは間違いなくマップによって消費されたメモリを解放します。


2
iframeの各インスタンスは、マップAPIをリロードする必要がありますが、これは理想的ではありません。
チャドキリングスワース2013

1

あなたが削除するとdiv、それが表示パネルを削除し、マップが表示されなくなります。マップインスタンスを削除するには、マップへの参照がに設定されnullていること、およびマップの他の部分への参照がに設定されていることを確認してくださいnull。その時点で、「JavaScriptでガベージコレクションはどのように機能しますか?」で説明されているように、JavaScriptガベージコレクションがクリーンアップを処理します。


1
map変数をnullに設定すると、すべてのイベントリスナーが適切に削除されるかどうかはわかりません。
チャドキリングスワース2012年

1
に設定する必要があるのはマップだけではなく、null他のものへの参照です。したがって、マーカー参照がに設定されnullていて到達不能になっている場合、イベントリスナーに到達する方法はありません。それはまだマップに接続されている可能性がありますが、マップに到達できないため、本質的に孤立したメモリの大きな塊にすぎません。Array.length = 0;を設定するのと同じです。メンバーへの他の参照がない場合、それらはガベージコレクションの対象となる孤立したメモリのグループを形成するだけです。
ショーンミッキー

0

私はあなたが話していると思いますaddEventListener。DOM要素を削除すると、一部のブラウザーはこれらのイベントをリークし、削除しません。これが、要素を削除するときにjQueryがいくつかのことを行う理由です。

  • を使用できる場合は、イベントを削除しますremoveEventListener。つまり、この要素に追加したイベントリスナーとの配列を保持しているということです。
  • 使用できない場合は、DOM要素で使用しているイベント(onclickonblurなど)に関する属性を削除します(それでも、追加されたイベントを格納する配列があります)。deleteaddEventListener
  • nullIE6 / 7/8のメモリリークを回避するように要素を設定します。
  • 次に、要素を削除します。

私は主に内部のGoogleMapsAPIイベントについて言及しています。これらは、developers.google.com / maps / documentation / javascript /…に記載されているAPIイベントメソッドを使用して追加/削除/トリガーできます。。ブラウザのaddEventListenerと機能的に類似している間、カスタムイベントの特定の多数はそのようなマップイベント「をサイズ変更する」などのブラウザイベントに「のbounds_changed」と、それらのイベントハンドラフックの一部として(マップにある
チャドKillingsworth

次に、追加されたイベントの配列を保持し、削除してから、イベントの種類を使用して、removeEventListenerまたはそれにdelete応じて手動で削除します。
Florian Margaine 2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.