読者です 読者をやめる 読者になる 読者になる

Jasyを使ってJavaScriptアプリケーションを作成する - 最適化

Zynga JavaScript Python

Jasy/Coreの使い方をなんとなく語るシリーズの第一回。順番が間違っている気がするが、第一回はJasyのJavaScript最適化機能について。

解説の順番が間違っている気がするが、Python3.2とpipをインストールした上で、

$ pip install https://github.com/wpbasti/jasy/zipball/0.4.6
$ git clone git://github.com/csakatoku/my-jasy-sandbox.git
$ cd my-jasy/sandbox/helloworld
$ jasy jasyscript.py build

ビルドを行なっていただければ、Jasyがどんなものか何となく分かると思う。


Jasyは"variables", "declarations", "blocks", "privates"の4つの最適化オプションを提供している*1。それらがどのようなものかをざっと説明する。僕は"variables"と"privates"オプションが気に入っていて、あえて地雷を踏みに行くJasyを使うメリットの一つだと思っている。

なお以下の例にあるJasy適用後のJavaScriptコードは著者によって読みやすいようにインデントして、コメントを追加してあります。実際の出力は無駄なホワイトスペースとコメントはすべて除去されます。

privates

__で始まるプロパティやメソッドを、以下の__fRv76ように一意でランダムなプロパティ名に書き換えてくれる。ちなみに、Jasyでは__で始まるプロパティやメソッドはプライベート扱いになり、これらのプロパティ、メソッドに外からアクセスしようとするとビルド時にエラーになる。

最適化前。

core.Class("p.helloworld.App", {
  construct: function(settings) {
    $("#content").html(this.sayHello());
  },

  members: {
    __name : 'Jasy',

    sayHello: function() {
        return "Hello, " + this.__name + "!";
    }
  }
});

Jasy適用後。

core.Class("p.helloworld.App", {
  construct: function() {
    $("#content").html(this.sayHello())
  },
  members: {
    __fRv76: "Jasy", // プロパティ名がランダムでユニークな文字列になっている
    sayHello: function() {
      return "Hello, " + this.__fRv76 + "!"
    }
  }
});

blocks

ifブロックを二項演算子を使って短縮してくれる機能。

適用前。

core.Class("p.helloworld.App", {
  construct: function(settings) {
    var __spam = "spam";
    var __egg = "egg";

    if (__spam) {
      console.log(__spam);
    } else {
      console.log(__egg);
    }
  }
});

適用後。

core.Class("p.helloworld.App", {
  construct: function() {
    var __spam = "spam";
    var __egg = "egg";
    __spam ? console.log(__spam) : console.log(__egg) // ifが消えた
  }
});

variables

ローカル変数を短縮してくれる機能。

適用前。

core.Class("p.helloworld.App", {
  construct: function(settings) {
    var __spam = "spam";
    var __egg = "egg";

    if (__spam) {
      console.log(__spam);
    } else {
       console.log(__egg);
    }
  }
});

適用後。

core.Class("p.helloworld.App", {
  construct: function() {
    var a = "spam"; // 長い変数名がaに変わっている
    var b = "egg";
    if (a) {
      console.log(a)
    } else {
      console.log(b)
    }
}});

declarations

変数宣言を短縮してくれる機能。

core.Class("p.helloworld.App", {
  construct: function(settings) {
    var __spam = "spam";
    var __egg = "egg";

    if (__spam) {
      console.log(__spam);
    } else {
      console.log(__egg);
    }
  }
});

適用後。

core.Class("p.helloworld.App", {
  construct: function() {
    var __spam = "spam", __egg = "egg"; // varがひとつ減っている
    if (__spam) {
      console.log(__spam)
    } else {
      console.log(__egg)
    }
  }
});

全部適用

全部の最適化を適用すると元の236バイトのスクリプトが170バイトになった。

core.Class("p.helloworld.App",{construct:function(){$("#content").html(this.sayHello())},members:{__fRv76:"Jasy",sayHello:function(){return"Hello, "+this.__fRv76+"!"}}});

Jasyで最適化できないこと

デッドコード削除は現状できていないし、ロードマップにあるのかも分からない。例えば、少しトリビアルな例だが、

function f() {
  if (0) {
    return "spam";
  } else {
    return "egg";
  }
}

は、if(0)が絶対成立しないので、

function f() { return "egg" }

と同等であるがJasyはこの部分を除去してくれない。

ただ、開発版でのロギングといったコードの削除ならば、多少冗長なのだが、core.Env.isSet("debug") で条件分岐を作ればリリース版では除去することができる。

function f() {
  if (core.Env.isSet("debug")) {
    // 開発版だけで行う処理
    console.log("very very verbose debug log");
  }
  // 何らかの処理
  alert("hello world");
}

適用結果。

function f() {
  alert("hello world");
}

*1:4.6 stable, 5.0 alpha現在