ShowTable of Contents
はじめに
XPages アプリケーション開発で、「可視」設定ので「値の計算」はパフォーマンス低下を招く可能性があります。「可視」評価の Javascript に複雑な処理を実装する必要があるときには、そのスクリプトが思いがけずに複数回実行されることがあり、それがパフォーマンスの低下につながります。この問題を考えるとき、XPages の処理の木曽となっている JavaServer Faces (JSF) のライフサイクルを理解する必要があります。以下の記事は XPages と JSF ライフサイクルの関係を解説し、「可視(rendered)」プロパティの問題について解説しています。
また以下の記事は、XPages アプリケーションの中で実際に JSF のライフサイクルの動きを調べるための方法について解説しています。
XPages 内の JSF ライフサイクルのフェーズを表示する方法
この記事では、JSF ライフサイクルを考慮して、「可視」プロパティの実践的な設定方法を検討します。
「可視」プロパティの問題と解決策
先のふたつの記事で解説したように、XPages のフレームワークである JSF ライフサイクルからみると、XPages のコントロールに対する評価は一回ではなく、複数回行われることがあります。このような XPages の仕組みを理解せずにアプリケーションを開発すると、予想外のオーバヘッドが発生し、アプリケーションのパフォーマンスの低下を引き起こすばかりではなく、サーバーの負荷増大やメモリリークの間接的原因ともなります。
特にコントロールの可視設定を制御する「可視(rendered)」プロパティには注意が必要で、画面更新時に4回呼び出されたり、ページの部分更新で更新の対象でもないのに呼び出されることがあります。そのため「rendered」プロパティには、処理の重いスクリプトを実装することは避けたほうが良いでしょう。
しかし、実際のアプリケーション開発ではコントロールの可視設定を行う必要は必ず出てきます。そしてそのようなときに Lotus Notes アプリケーションなどのデータを参照したいということはありえるでしょう。では、そのようなときにはどのように実装すべきか?
「rendered」プロパティに重い処理の実装することでのパフォーマンスの低下を避けるための方法として、以下のような方法があります。
-
プロパティの「値の計算」で「動的に計算」ではなく「ページの呼び出し時に計算」を選択する。
-
「rendered」プロパティではなく、「loaded」プロパティを使用する。
-
スコープ変数を使って同じ処理を繰り返さない。
-
view.isRenderingPhase() メソッドで Rendering フェーズのみで処理を行う。
プロパティの計算でく「ページの呼び出し時に計算」を選択する
「可視(rendered)」プロパティだけではないですが、「値の計算」で表示されるスクリプトエディタでは、値の計算のタイミングとして「動的に計算」と「ページの読み込み時に計算」のいずれかを選択することができます。「動的に計算」を選択すると、先の記事に紹介したように複数の JSF フェーズでスクリプトの処理が実行されてしまいます。「ページの読み込み時に計算」を選択することで、Restore View フェーズでのスクリプトの実行となり、スクリプト処理の負荷を下げることができます。しかし、「ページ読み込み時に計算」を選択すると、スクリプトの評価はページ生成時のみとなり、更新時には評価されません。また Restore View フェーズで処理が行われるため、ページ内のコントロールが実体化されておらず、コントロールの値を取得できないといった制限もあります。
ところで、「動的に計算」と「ページの読み込み時に計算」とで XPages のソース上でどのような違いがあるかご存知でしょうか?
以下のふたつのボタンの「rendered」プロパティでは、プロパティの値の最初の記号が「#」と「$」と異なります。「動的に計算」では「#」となり、と「ページの読み込み時に計算」は「$」です。
<xp:button value="編集1" id="button1" rendered="#{javascript:!currentDocument.isEditable()}"></xp:button>
<xp:button value="編集2" id="button2" rendered="${javascript:!currentDocument.isEditable()}"></xp:button>
「rendered」プロパティではなく、「loaded」プロパティを使用する
「読み込み(loaded)」プロパティは、ページの読み込み時にコントロールを生成するかどうかを判別するためのプロパティです。ここに「値の計算」を指定することで RestoreView フェーズでコントロールを読み込むかどうかの判定ができます。しかし、このプロパティはページの読み込み時の判定なので、先に紹介した「可視(rendered)」プロパティでの「ページの読み込み時に計算」を選択したときと同じ様な制限があります。
スコープ変数を使うなどして同じ処理を繰り返さない
スクリプトの処理を一度だけ行ってその結果をスコープ変数に格納し、「可視(rendered)」の「値の計算」ではその変数を参照します。
以下の実装例では表示の判別を、その判別に影響する事象が起こったところで計算して viewScope 変数に格納し、「可視(rendered)」プロパティではその結果のみの評価をするように実装しています。
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:checkBox id="checkBox1" text="showLabel">
<xp:eventHandler event="onchange" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:viewScope.showLabel = getComponent("checkBox1").isChecked();}]]></xp:this.action>
</xp:eventHandler>
</xp:checkBox>
<xp:label value="Can you see me ?" id="label1" rendered="#{javascript:viewScope.showLabel}"></xp:label>
</xp:view>
Render Response フェーズのみで処理を行う
最後に紹介するのは JSF の Render Response を判別して処理を行う方法です。JSF ライフサイクルの理解が必要ですが、先に紹介した手法に比べて単純で、既存のアプリケーションの改修には使いやすいでしょう。
XPages のサーバーサイド Javascript で利用できる「view」グローバル変数には isRenderingPhase() メソッドがあります。このメソッドで RenderResponse フェーズを判別して処理を実装することができます。
<xp:button value="編集3" id="button3">
<xp:this.rendered><![CDATA[${javascript:
if (view.isRenderingPhase()) {
!currentDocument.isEditable()
}
}]]></xp:this.rendered>
</xp:button>
まとめ
この記事では「可視」評価のパフォーマンス改善について解説しました。
やり方はいろいろあり、最後に紹介した Render Response フェーズを判別するやり方が簡単そうですが、非表示の条件をよく吟味することで、元の設定変更時に計算してスコープ変数に入れたり、あるいはページ生成時に評価すれば十分ということもあるかもしれません。XPages アプリケーションでより良いパフォーマンスを出すために、実装しているアプリケーションの仕組みを理解して、これらの方法を適用してください。