rss
3

Improve XPages Performance With view.isRenderingPhase()

Well, well – a full 82 days have passed since my initial statement of intent and I am finally moved to make a first meaningful blog post. Although a little abashed that it has taken so long, I am comforted by the thought of a phrase often used by my late Grandfather:

The trees that are slow to grow bear the best fruit.

I have waited nigh on thirty five years for the opportunity to use that particular quote in a written article, although I did use it once in a futile discussion about rapidly disappearing deadlines with a humourless project manager.
Humour was a commodity my Grandfather was not short of together with an abundance of wisdom and he also imparted to me the following words of advice:

There are three things in life you do not want to understand the inner workings of:
1. How sausages are made.
2. How laws are passed in a (supposedly) western democracy.
3. The JSF lifecycle.

I am fairly sure that he was definitely correct about number one and probably also number two. However, it turns out that for all his years of accumulated knowledge my Grandfather’s advice in respect of the JSF lifecycle was misguided.
Now, to be perfectly clear, this small article is by no means a deep dive into the JSF lifecycle from the perspective of an XPages developer but is simply a tip on one small feature that (along with many others) can improve the performance of your applications.

There are six phases to the JSF lifecycle:

  1. Restore View
  2. Apply Request Values
  3. Process Validations
  4. Update Model Values
  5. Invoke Application
  6. Render Response

Components on the XPage can be calculated in more than one phase of the JSF lifecycle. To give just one example, SSJS in a computed field is evaluated in the Apply Request Values and the Render Response phases.
What can be surprising to learn is that a rendered property is evaluated in no less than four of the six phases, namely Apply Request Values, Process Validation, Update Model Values and Render Response.
This should give pause for thought and if nothing else is a convincing argument for the use of Partial Execution (so only the components within the execID are recalculated during the JSF lifecycle). The estimable Mr Withers explains Partial Execution here and if you are not already familiar with this XPages feature then I urge you to stop reading this drivel and click on the aforementioned link this instant.

Now imagine if we have some heavy lifting SSJS as part of a rendered calculation or worse, several of them perhaps doing expensive look ups. These evaluations are being performed three times more than we instinctively think.

This is where view.isRenderingPhase() becomes very useful. This simple method returns true or false dependent upon whether the current lifecycle phase is Render Response.

Consider the code snippet below. This is a simple XPage with two computed fields and a button that does a full refresh (this could be a partial refresh and the full XPage component tree would still be calculated by the server unless partial execution is used).
Each computed field has a rendered property that is calculated using SSJS. There is a comment where the heavy lifting code would be in a real world application and a simple print statement to the console.

If you copy and paste this code into an XPage, view it, click the button and examine the output to the console you will see that the rendered code for the first computed field is calculated four times as outlined above.
The code for the second computed field which has a conditional check using view.isRenderingPhase() is only evaluated the once. This is highlighted in lines 18 – 25.


<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">


	<xp:text escape="true" id="computedField1"
		value="#{javascript:java.lang.System.currentTimeMillis()}">
		<xp:this.rendered><![CDATA[#{javascript:
			print('Calculating rendered property for computedField1') ;
			var renderResult = true ;
			return(renderResult) ; }]]>
		</xp:this.rendered>
	</xp:text>

	<br /><br />

	<xp:text escape="true" id="computedField2"
		value="#{javascript:java.lang.System.currentTimeMillis()}">
		<xp:this.rendered><![CDATA[#{javascript:
			var renderResult = view.isRenderingPhase() ;
			if (renderResult) {
				//Heavy lifting here: renderResult = result of heavy lifting calculation
				print('Calculating rendered property for computedField2') ;
			}
			return(renderResult) ; }]]>
		</xp:this.rendered>
	</xp:text>

	<br /><br />

	<xp:button value="Submit" id="button1">
		<xp:eventHandler event="onclick" submit="true"
			refreshMode="complete">
		</xp:eventHandler>
	</xp:button>


</xp:view>

This can be a very useful technique in certain scenarios and used together with other powerful XPages features such as partial execution, partial refresh and the loaded property can really make a difference to application performance.

As my Grandfather would undoubtedly say

Job’s a good’un

Comments (3)

Trackback URL | Comments RSS Feed

  1. Paul Withers says:

    Great tip. I really need to look at all the properties and methods of the in-built objects.

    Taking it to the nth degree (because there’s always somewhere deeper down the rabbit hole you can go with XPages), if you wanted to streamline code further, you could create a dataContext with var=”renderResult” and value=”#{javascript:view.isRenderingPhase()}”.

    If you want to go deeper, I believe value=”#{view.renderingPhase}” should work as Expression Language, to (minimally) speed up performance and typing. EL in this context calls the relevant method – e.g. getRenderingPhase or setRenderingPhase if the property was a string, or because it’s a boolean isRenderingPhase. The key is that the “r” or renderingPhase automatically gets capitalised after the “is”,”get” or “set”). The dataContext just needs to be on each page it’s used.

    You could use a VariableResolver for greater reusability, either in each NSF or in your own Extension Library. But the trade-off is that you have an extra if statement running for every variable (e.g. view, database, session, or “var” property on components).

  2. A very interesting idea, but you can get in trouble if a component is only visible in a single phase of the whole JSF lifecycle: If you are rendering a component in the last phase only, all validators and converters will not work anymore. It is better to do the calculation in the first phase and cache the result, but this is a litle bit tricky, because the Restore View phase is skipped if the XPage is opened for the first time…

  3. Don Mottolo says:

    Good post – good information and enjoyable to read! (I, for one, am glad that you “don’t give a &^%$ what anyone thinks anymore”.) I know that I should learn more about the JSF lifecycle, and posts like this may actually inspire me to do so (and perhaps do some blogging as well).

Leave a Reply




If you want a picture to show with your comment, go get a Gravatar.