maio 26, 2010

Otimização do RichFaces e consciência no uso do ajax

Este post nasceu por causa de uma dificuldade encontrada em um projeto que encontrava-se na reta final, e tivemos que realizar algumas mudanças para obter a melhor performance e ter um melhor aproveitamento dos componentes que estavamos usando.Chega de papo furado, vamos ao que interessa. =)
O cenário em questão é JSF + RichFaces e a utilização do recurso Ajax. Após diversas e demoradas pesquisas na internet atrás de soluções aplicaveis ao meu contexto de uso, achei alguns pontos interessantes para a performance das requisições e outras mais para a otimização do sistema. Daí você me pergunta, qualé a diferença de performance das requisições para a otimização do sistema???

A otimização do sistema envolvendo o Richfaces é na hora de carregar o sistema no cliente. Nas configurações que é feito no arquivo web.xml, você tem alguns "macetes" que trazem alguma otimização para o sistema, em questão de banda, por exemplo.

<context-param>
<param-name>org.ajax4jsf.COMPRESS_SCRIPT</ param-name>
<param-value>true</param-value>
</context-param>

Esse trecho significa que antes de enviar para o cliente todas os scripts, ele irá compacta-los e somente depois, enviar um único arquivo compactado, contendo todos esses arquivos, sendo assim, tendo uma otimização do carregamento do sistema no cliente. :D

<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter </filter-class>
<init-param>
<param-name>forceparser</param-name>
<param-value>false</param-value>
</init-param>
</ Filter>

Com essa configuração 'true' o filter interpreta que TODAS as respostas deverão passar pelo parser,
que tem um custo para essa tarefa, e deixando ele como 'false', apenas as reponse ajax terão que ter
o parse  ajustado. Em uma aplicação com telas complexas, o ganho é consideravel. =)

<context-param>
<param-name>org.richfaces.LoadStyleStrategy </param-name>
<param-value>all</param-value>
</context-param>

Essa configuração informa ao container descarregar todos os arquivos de stylesheet no cliente na primeira requisição do cliente ao sistema, ou quando eles expirarem, claro. Uma vez carregados, o seu trafego de dados diminui e com isso suas request/response tendem a serem mais rápidas. :P

<context-param>
<param-name>org.richfaces.LoadScriptStrategy </param-name>
<param-value>all</param-value>
</context-param>

É o mesmo caso da configuração dos arquivos de stylesheet, porém nesse caso, serão os arquivos de javascript, scripts e relacionados que serão carregados uma única vez no cliente. Se já teve a curiosidade de ver a quantidade de scripts que o RichFaces possui, imagina que isso realmente pode ser vantajoso. =}

<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
<init-param>
<param-name>enable-cache</param-name>
<param-value>true</ param-value> </init-param>
</filter>

Essa parte é pra habilitar no cliente o cache dos componentes do RichFaces. Uma boa, porque o RichFaces possui vários bibliotecas de JS, stylesheet, então deixando-as no cliente, é menos trafego.

<context-param>
<param-name>org.ajax4jsf.xmlparser.ORDER</param-name>
<param-value>NEKO</param-value>
</context-param>

<context-param>
<param-name>org.ajax4jsf.xmlparser.NEKO</param-name>
<param-value> .* \ ..*</param-value>
</ context-param>

O padrão de parser do RichFaces é o Tidy, que por ventura é mais lento que o Neko, então aqui estamos informando ao container que é para utilizar o Neko, e o parser será utilizada nas páginas de todas as hierarquias do projeto (.*\..*).
Tudo descrito acima é para a otimização do sistema, porque essas configurações tem por finalidade otimizarem o carregamento dos componentes na tela, utilizando-se de compactações e cache no lado cliente, que fará que um o sistema seja carregado mais lento na primeira vez, para se ter ganhos subsequentes. =D

Agora vem a parte diretamente ligado ao Ajax do RichFaces, que no meu caso, foi o meu maior vilão, e depois de compreendido, tornou-se meu maior aliado (bonito isso não?).

AjaxSingle = true
A utilização desde atributo, verdadeiro, faz com que o mapa de requisições ajax seja desprezado, e o envio para o servidor é apenas para o atributo em questão. Exemplo: Combos de Estado e Municipio, para atualizar o municipio, você precisa apenas do Estado.

limitToList = true
Esse atributo é bem útil e interessante, quando conhece a sua finalidade e o seu uso é no lugar devido. Quando verdadeiro, ele assegura que apenas os id's que estão no reRender do componente serão atualizados. É o caso de uma página com diversos campos, e você precisa apenas atualizar o municipio, utilizando-se deste atributo e no reRender você informar o id do municipio, o response ajax, irá atualizar apenas o municipio, e não irá passar nos get's dos outros atributos. :)
* Essa limitação é valida para os componentes que utilizando de ajaxRendered = true (a:form, a:outPutPanel e a:panel)

immediate = true
Quando verdadeiro, força o JSF a pular a fase de validação do objeto e ir imediatamente para a fase de atribuição dos valores ao objeto. Menos uma fase do JSF, mais ágil se torna o request.

process = id's
O uso deste atributo juntamente com o ajaxSingle, limiToList e immediate diria eu, que é o casamento perfeito :D. Neste atributo você informa o id's que serão necessários para realizar algum tipo de request. Exemplo: Para atualizar o municipio, você precisa ter o valor do estado, se você utilizar o ajaxSingle=true e immediate=true, provavelmente ele não irá postar nenhum valor, mas, utilizando-se dos mesmos e também o process=idEstado, você irá forçar que o JSF na hora de enviar a requisição do estado, e para reRender o municipio ele precisa do atributo 'idEstado' e com isso o valor será passado ao set do atributo, e podendo assim, atualizar a lista de municipios. :D

region
É uma propriedade assim como o a:outPutPanel, a:form e a:panel, porém, com a funcionalidade de limitar-se uma região onde determinadas informações serão reRenderizadas. Exemplo: De uma página que você precise atualizar vários campos em detrimento de uma opção escolhida, ao invez de passar vários id's, você pode deixa-los dentro de uma region, e reRenderizar, apenas este.

dataTable
A utilização das tabelas do RichFaces(rich:dataTable e rich:extendedDataTable) devem ser somente em casos que você precise realmente de componentes com mais recursos, quando a necessidade for apenas exibir informações para o usuário, utilize o h:dataTable. Em último caso use o richExtendedDataTable, porque é a tabela com maiores recursos e maior custo de renderização dos componentes.

Espero que este post tenha ajudado-lhe de alguma forma, porque perdi algumas várias horas pesquisando e lendo informações as vezes de ctrl+c e ctrl+v na internet que ao invez de ajuda, me trouxeram mais dúvidas, e depois de muita luta aprendi a utilizar estes recursos de maneira e me proporcionarem o melhor que si, e não o contrário.

Good luck ;-)

Posts Relacionados