LoginSignup
14
8

More than 1 year has passed since last update.

利用ケースからWeakMapを理解する

Last updated at Posted at 2017-06-13

WeakMap概要

Mapと違って、キーとして使われるオブジェクトが生きているうちに、WeakMapがキーの参照を持ちますが、WeakMap以外誰にも使われていなければ、ガベージコレクションによってキーオブジェクトのメモリを解放してしまいます。つまり、キーの参照が弱い参照であり、自動的に削除される可能性があります。
次は、利用ケースでなぜWeakMapが必要なのかを理解しましょう。

利用ケース

下記execute関数が複数回に呼ばれることがあり、同じ引数objで実行される回数が10の倍数になったら、そのobj情報をシステム上に通知を行います。

// マップキーが文字列ではなく、オブジェクトです
let map = new Map();

function execute(obj){
  doSomethingWith(obj);

  // 既存の回数を取得
  const called = (map.get(obj) || 0) + 1;
  map.set(obj, called);

  // 10回目で
  if(called % 10 === 0) {
    report(obj);
  }
}
  • 上記実装の問題点

 例え、上記objがシングルページアプリケーションのDOMエレメントの場合、DOMが大量に生成されたり、破棄されたりとします。破棄されたDOMエレメントが上記回数を統計するmapのキーになっているため、GC処理対象外になり、メモリリークが発生してしまいます。
 本来は、生きているDOMエレメントを絞って統計したいにもかかわらず、死んでしまったDOMエレメントの情報も残されてしまいます。

  • 考えられるアプローチ:DOMエレメントのdeleteイベントでmapから削除する

 DOMエレメントのdeleteイベントを監視し、発生したらmapから該当objを削除するように実装すれば、メモリリーク問題が解決になります。
 ただ、そうしますと、監視マップとDOMエレメントが相互的に相手の存在を意識しなければならないし、処理も複雑になり、バグが入りやすいですね。
 いよいよWeakMapの登場です。

  • WeakMap案

GCによりキーオブジェクトの廃棄と共に、WeakMapから該当データが自動的に削除されるので、実装がシンプルになります。

// マップキーが文字列ではなく、オブジェクトです
let map = new WeakMap();

function execute(obj){
  doSomethingWith(obj);

  // 既存の回数を取得
  const called = (map.get(obj) || 0) + 1;
  map.set(obj, called); // 設定したが、GCにより自動的に削除される

  // 10回目で
  if(called % 10 === 0) {
    report(obj);
  }
}

参考記事

WeakMap(MDN)
What are the actual uses of ES6 WeakMap?

14
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8