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 ;-)

4 comentários:

  1. muito bom! show de bola! também estava com dúvidas a respeito destas propriedades

    ResponderExcluir
  2. ótimo post, apliquei todas no projeto da empresa que estou trabalhando. obrigado.

    ResponderExcluir
  3. Ótimo artigo!!!
    Se tivesse o botão de curtir eu curtiria, como não tem, vou twittar!!!
    Agora dá licença que vou usar essas técnicas no meu projeto!!!
    Um Abraço!

    ResponderExcluir
  4. Cara ótimo, fiquei mais por dentro das ferramentas do Richfaces.
    Ótima explicação
    show !!!

    ResponderExcluir

Posts Relacionados