Monday, 27 January 2014

Salesforce.com - Optimization of View State

Most of the time we did not consider the view state during development, but it is one of the most important aspect to keep in mind during VisualForce development. it will help you to increase the performance of Visualforce and improve the user experience. We should know how can we optimize the VF page and view state, but first something on view state...

What is view state?

You know that HTTP is a stateless protocol, it means request for any new page (called GET request) or clicking on any button with form's data ( called POST request) will be treated as  new independent requests.



What will the impact if there is no view state?


Assume that you are filling a registration form and there are 10-15 fields on the page, after filling all information you click on submit button and you will get a invalid date error message on your page and you will loose all form data,because HTML forms does not have capability to store input data, you need to fill it again. Now view state comes in action, In general, its encrypted data to store fields values of any form.


How do Visualforce maintain the view state?


In Visualforce, page state is persisted as a hidden form field that is automatically inserted into a form when the page gets generated. It can be called as page's view state and it captures the state of the page. The state of its associated controllers and extensions and the component tree on the page. 
The view state is posted back along with the other form data, which gives the server enough information to recreate the page state to which new changes can be applied. 

Visualforce pages that contain a form component also contain an encrypted, hidden form field that encapsulates the view state of the page. This view state is automatically created, and as its name suggests, it holds the state of the page - state that includes the components, field values and controller state.In short,

If there is a <apex:form> in your page, there must be a hidden form field for view state.

View state required for few components:
<apex:action*>
<apex:command*>
<apex:inlineEditSupport>
<apex:input*>
<apex:select*>


How can we optimize the view state?

  • You should reduce the number of components
  • You should use transient whenever possible
  • You should JavaScript Remoting (if possible)
  • Use of Streaming API

Reduce the number of components:


You should minimize the number of Forms on a page as well as number of components which require view state. You should use;
 <apex:outputPanel>
 <apex:outputLink>
 <apex:outputText>
 <apex:panelGrid>


whenever possible and instead of using multiple Forms on a page, you should you use <apex:actionRegion> to submit a portion of the form.This practice will ensure that only a single copy of the view state is associated with that page.
// Using two forms
<apex:page controller="YourController">
<apex:form>
   <apex:commandButton action="{!saveAccount}" value="Update Account"/>
    <!--Account attributes available for editing -->
</apex:form>
<apex:form>
    <apex:commandButton action="{!saveContacts}" value="Update Contacts"/>
     <!--Contact attributes available for editing -->
</apex:form>
</apex:page>
// Combining into single form and leveraging <apex:actionRegion>
<apex:page controller="YourController">
  <apex:form>
     <apex:commandButton action="{!saveAccount}" value="Update Account"/>
     <!--Account attributes available for editing -->
     <apex:actionRegion>
       <apex:commandButton action="{!saveContacts}" value="Update Contacts"/>
     <!--Contact attributes available for editing -->
    </apex:actionRegion>
  </apex:form>
</apex:page>


Use Transient keyword:


To reduce the view state size, you should you the Transient before LIST,SET,MAP and Properties if values are no longer required in duration of page request. An instance variable declared as transient is not saved and is not transmitted as part of the view state.

transient public List<Contact> lstContacts {set;get;}


JavaScript Remoting:


It is a stateless way to call Apex controller methods from JavaScript. If you call a method through JS It will never save its state and increase the page performance.

For ex: Account Search with JavaScript Remoting, it will increase the performance 35% compare to commandbutton or commandlink etc. 
global with sharing class AccountRemoter { public String accountName { get; set; } public static Account account { get; set; } public AccountRemoter() { } // empty constructor @RemoteAction global static Account getAccount(String accountName) { account = [SELECT Id, Name, Phone, Type, NumberOfEmployees FROM Account WHERE Name = :accountName]; return account; } }
<script type="text/javascript">
   function getRemoteAccount() {
      var accountName = document.getElementById('acctSearch').value;
       Visualforce.remoting.Manager.invokeAction(
             '{!$RemoteAction.AccountRemoter.getAccount}',
            accountName, 
            function(result, event){
             if (event.status) {
               document.getElementById('remoteAcctId').innerHTML = result.Id
               document.getElementById(
             "{!$Component.block.blockSection.secondItem.acctNumEmployees}"
            ).innerHTML = result.NumberOfEmployees;
      } else if (event.type === 'exception') {
         document.getElementById("responseErrors").innerHTML = 
         event.message + "<br/>\n<pre>" + event.where + "</pre>";
       } else {
       document.getElementById("responseErrors").innerHTML = event.message;
       }
        {escape: true}, 
       }
       );
      }
</script>
  <input id="acctSearch" type="text"/>
   <button onclick="getRemoteAccount()">Get Account</button>
   <div id="responseErrors"></div>
  <apex:pageBlock id="block">
       <apex:pageBlockSection id="blockSection" columns="2">
           <apex:pageBlockSectionItem id="firstItem">
               <span id="remoteAcctId"/>
           </apex:pageBlockSectionItem>
           <apex:pageBlockSectionItem id="secondItem">
               <apex:outputText id="acctNumEmployees"/>
           </apex:pageBlockSectionItem>
       </apex:pageBlockSection>
   </apex:pageBlock> 
</apex:page> 


Refine Your SOQL to Retrieve Only the Data Needed by the Page


Only retrieve (and store) the fields you need and also filter the data to only retrieve data needed by the page.

Streaming API:


A highly performed  way to get information from Salesforce.com instance without polling.
If your application is currently polling the SOAP or REST API to detect changes, you should consider refactoring it to use the Streaming API; you will see better performance with lower resource consumption.

No comments:

Post a Comment