Skip to content

Instantly share code, notes, and snippets.

@uupaa
Last active August 1, 2018 15:08
Show Gist options
  • Select an option

  • Save uupaa/8d2e5b19c1a1ef267ec2 to your computer and use it in GitHub Desktop.

Select an option

Save uupaa/8d2e5b19c1a1ef267ec2 to your computer and use it in GitHub Desktop.
ES6 WeakSet usecase

ES6 (ES2015) で追加された WeakSet は、かなり使い方が限定された(≒ まだ有効な使い方があまり見つかっていない)コレクションクラスです。

Task.js では、この WeakSet を現在実行中のインスタンスの一覧を開発者に提示する Task.dump() 機能で利用していますので、その背景と使い方について軽く説明をしてみたいと思います。

Task.js が WeakSet を使って実装されたのはごく最近の事です。
初期の Task.js のデザインではこのようになっていました。

初期の Task.js の実装

https://github.com/uupaa/Task.js/blob/1798bcd241b7ac9268d3e7eedd39b40ae5107d06/lib/Task.js

  • 実行中のインスタンスを保持するコレクションクラスには Object を使用しています
  • _taskCount にインクリメントする値を格納しています
  • Object の key の衝突(上書き)問題を防ぐためにユニークな名前を生成(name + "@" + _taskCount)しています
var _taskInstances = {}; // instances. { "taskName@counter": TaskInstance, ... }
var _taskCount = 0;

function Task(...) {
  this["name"] = name + "@" + (++_taskCount); // String: "task@1"
  _taskInstances[this["name"]] = this; // register task instance.
}
Task["dump"]      = Task_dump;      // Task.dump(filter:String = ""):Object
Task["clear"]     = Task_clear;     // Task.clear():void

function _update(...) {
  if (処理終了) {
    delete _taskInstances[that["name"]]; // [!] GC
  }
}

function Task_dump(...) {
    return JSON.parse( JSON.stringify(_taskInstances) ); // dead copy
}

function Task_clear() { // @desc clear snapshot.
    _taskInstances = {}; // [!] GC
    _taskCount = 0;      // [!] reset count
}

ちょっと、ごちゃごちゃしてしまっていますね。

Version 1.0.0 以降の Task.js の実装

Version 1.0.0 以降ではこのようになっています。

https://github.com/uupaa/Task.js/blob/5f3c7bfa459500b773844955ae1186845fc454fb/lib/Task.js

  • _taskInstances, _taskCount, Task.clear() を廃止しました
  • Task.dump はインスタンスのスナップショット(WeakSet)を返すようにしました
function Task(...) {
  Task.snapshot.add(this);
}
Task.snapshot = new WeakSet(); // { TaskSnapShot, ... }
Task["dump"] = function() { return Task.snapshot; }; // Task.dump():TaskSnapShotWeakSet

function _updateState(...) {
  if (処理終了) {
    Task.snapshot.delete(that); // [!] GC
  }
}

Task.dump が返す値は、静的なものではなく動的な値です。
インスタンス名を直接指定することでコンソールから操作を加える事も可能ですが、 その場で状況を確認する用途に特化しています。

また、不要になったインスタンスは自動的に消滅します。
このようなケースでは WeakSet はとても便利ですね。

TODO: 時間切れ。ざっくり書き過ぎなので、もうちょっと続き書く

ES.js をロードすると、WeakSet が存在しない環境でも動作します。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment