画面描画が遅い画面の原因をさぐりたい

「同じような作りをしている複数の画面のうち、1つだけ妙に画面描画(メニュークリックから初期画面表示まで)が遅いものがあるから調べてほしい」

これだけの情報だと、かなり漠然としているので調べるのは不可能に近いのですが、ソースも環境もあり、開発者にもヒアリングできるので行ってみようということになりました。

  1. まず、画面側(javascript)の問題なのか、サーバ側(Java)の問題なのかを切り分ける必要があります。この画面だけが遅いので、この画面特有の処理が最初に始まる部分を探し出し、この部分にデバッグポイントを設けました。なお、javascriptデバッグにはfirebugを利用しました。サーバ側のデバッグeclipseです。すると、この画面特有の処理が始まる以前が遅いということが分かりました。どのポイントにも到達するまえに遅いと言われている現象が発生したためです。
  2. 次にHTTP通信についてトレースしました。使用したのは、fiddlerhttp://www.fiddler2.com/Fiddler2/version.asp)です。
    • 通信の頻度
    • サーバとの通信でのファイルサイズ
    • 統計時間
    • タイムライン
  3. 最後にブラウザを使用しているPCのリソースをモニタリングしました。上の2番のタイムラインで遅くなっている時間帯には、ローカルPCのCPU使用率があがり、画面描画が終了するとCPU使用率が下がりました。またローカルCPU使用率が上がっている間にはHTTP通信は行われていませんでした。

もうこれは、javascriptでどこか悪さをしているということで、firebugの出番です。
画面の描画開始前に

console.profile("start");

と書き、描画終了のポイントに

console.profileEnd();

プロファイルを仕込んで実行すると以下のようなレポートが出力されます。

これによると、一番上にあるcreateTabIndexesという関数に約9秒ほど時間を費やしているようです。
これはマスカットの標準ソースなんですが、以下のようなコーディングになっています。

/**
 * このレイアウトに含まれるマスカット部品のうち、タブインデックスを
 * 持つものについて、タブインデックスの順序にソートされた配列を生成
 * します。
 */
createTabIndexes: function() {
  var indexes = [];
  var widget = null;
  var index = null;
	
  for (var i = 0; i < this.tabIndexes.length; i++) {
    widget = this.tabIndexes[i];
    index = widget.getTabIndex();
    if (widget && index > -1) {
      if (!indexes[index]) {
        indexes[index] = [];
      }
      indexes[index].push(widget.getWidgetId());
    }
  }
  var tabIndexes = [];
  while (indexes.length > 0) {
    index = indexes.shift();
      if (index) {
        Array.prototype.push.apply(tabIndexes, index);
      }
  }
  return tabIndexes;
},

どうやらマスカット部品の中でタブオーダーを指定可能なもののうち、一番大きな値でループするコーディングになっているみたいですね。
そこで、レイアウトXMLのtabindexに注目して調べてみると、画面描画の遅いもののtabindexの最大値は9999でした。
他の遅くない画面のtabindexの最大値は999でした。
tabindexの値を試しに9999->999に変更して実行したところ、約9秒かかっていたcreateTabIndexesの処理は、0.2秒ほどになりました。
※maskat-2.2.0.v20100618-src時点で、上のようなコーディングになっています。

マスカットをよく利用されている方の間では既知の問題なのかも知れませんが、tabindexの値はほどほどにしたほうが良いみたいですね。