Outubro de 2017

Volume 32 - Número 10

Desenvolvimento da Web - Sensações da Velocidade: O AJAX Gerenciado Poderia Deixar Seus Aplicativos Web Mais Velozes?

Por Thomas Hansen | Outubro de 2017

De acordo com diversos estudos sobre o assunto, duas das mais importantes preocupações ao criar um aplicativo Web AJAX são velocidade e capacidade de resposta. Essas provavelmente são algumas das razões pelas quais alguns desenvolvedores escolhem criar aplicativos nativos em vez de aplicativos Web. Mas e se eu lhe dissesse que existe um modo de criar aplicativos Web AJAX 100 vezes mais rápidos e responsivos do que aqueles conhecidos por você?

Inventei um modo de criar aplicativos Web AJAX 100% baseados em JavaScript puro, que reduzem o uso de largura de banda para seus aplicativos em pelo menos dez vezes, podendo chegar a 300 vezes, dependendo dos tipos de ferramentas que você está usando e no que você deseja criar. Chamo essa técnica de "AJAX Gerenciado".

AJAX Gerenciado é até certo ponto inspirado pelo modo como a Microsoft criou o CLR (Common Language Runtime). Por exemplo, quando você cria um aplicativo C#, o compilador cria um assembly CLR. Isso implica que o seu ambiente de tempo de execução para seu resultado final é um “ambiente gerenciado”. Quando você cria um aplicativo AJAX, seu resultado não é compilado para nada diferente de um site da Web ASP.NET simples normal; ele se torna um ambiente gerenciado, em que as partes em JavaScript dos seus resultados finais são completamente abstraídas, do mesmo modo que as instruções de CPU são abstraídas quando você tem um assembly CLR.

Como isso funciona?

O AJAX gerenciado não requer praticamente nenhum novo conhecimento. Se você já fez algum desenvolvimento ASP.NET, você pode soltar uma nova biblioteca de Controle em suas páginas .aspx e continuar seu trabalho, quase do mesmo modo como fez anteriormente. Você cria dois controles ASP.NET, seja em sua marcação .aspx ou em seu codebehind C#/F#/Visual Basic .NET. Em seguida, você decora as propriedades de seus controles, adiciona dois manipuladores de eventos AJAX e pronto!

A renderização inicial cria o bom e velho HTML para você. Mas toda alteração que você faz a qualquer um dos seus controles no lado do servidor durante uma solicitação AJAX é passada ao cliente como JSON. Portanto, o cliente pode sair disso como uma biblioteca JavaScript muito pequena, com menos de 5 KB de tamanho total, e você pode criar controles AJAX avançados como TreeViews, DataGrids e TabViews, sem nunca precisar usar mais de 5 KB de JavaScript.

Perceba que, neste ponto, você já superou o jQuery como um arquivo JavaScript autônomo por praticamente uma ordem de magnitude (o jQuery versão 2.1.3, após minificação e compactação zopfli, tem 30 KB). Assim, apenas incluindo jQuery em sua página sem nenhum outro JavaScript, você já consumiu seis vezes mais largura de banda do que consumiria usando uma abordagem de AJAX gerenciado. Se você começar a consumir jQuery em seu próprio JavaScript, esse número cresce assustadoramente.

Efetuar o pull da interface do usuário do jQuery em sua versão minificada e compactada faz com que suas partes de JavaScript aumentem em 73,5 KB. Apenas incluir jQuery e a interface do usuário do jQuery em sua página aumenta o tamanho dele em 103,4 KB adicionais (103,4 KB divididos por 4,8 KB resultam em 21,5 vezes o consumo de largura de banda). Nesse ponto, você ainda não criou um único elemento de interface do usuário sequer, mas ainda assim a soma de jQuery + interface do usuário do jQuery consome praticamente 22 vezes o espaço de sua abordagem de AJAX gerenciado. E você pode criar praticamente todo widget de interface do usuário imaginável com esses 5 KB de JavaScript, incluindo a maioria dos controles de interface do usuário que a combinação de jQuery + interface do usuário do jQuery pode criar. Basicamente, independentemente do que você fizer, você raramente ou nunca excederá esse limite de 5 KB de JavaScript. As outras partes do seu aplicativo, tais como HTML e CSS, também poderão ter seus tamanhos muito reduzidos.

Usando essa abordagem, você cria controles de interface do usuário AJAX avançados, tais como controles TreeView, DataGrid e TabView do AJAX. E você nunca precisa de JavaScript adicional ao criar esses widgets. Também não é necessário nenhum conhecimento novo para usar esses controles. Você apenas utiliza-os (quase) do mesmo modo que consumiria um WebControl do ASP.NET tradicional.

A abordagem de AJAX gerenciado tem dois modos distintos de lidar com as solicitações HTTP para a sua página. Um dos manipuladores é uma solicitação HTTP simples normal, que apenas servirá HTML ao cliente. O outro manipulador permite que você verifique a existência de um parâmetro HTTP post. Se esse parâmetro existir, o manipulador renderizará somente as alterações feitas a cada controle de volta para o cliente como JSON. Durante uma solicitação do AJAX, cada controle criado pela modificação da hierarquia de controles da página será automaticamente recriado para você com as propriedades que ele tinha na sua solicitação anterior. No lado do cliente, você tem um manipulador geral que manipula suas propriedades JSON para seus controles e atualiza genericamente os atributos e manipuladores de eventos DOM dos elementos DOM no cliente.

Essa abordagem tem vários efeitos colaterais positivos como não combater o modo como a Web foi originalmente criada, pois renderiza os elementos HTML como exatamente isso – elementos HTML. Isso implica que, semanticamente, seus aplicativos Web se tornam mais facilmente compreendidos (por spiders de mecanismos de pesquisa, por exemplo). Além disso, ele cria um ambiente superior para modificar realmente coisas no cliente, caso você deseje usar o melhor de ambos os mundos.

Você ainda pode combinar essa abordagem com tanto JavaScript personalizado quanto desejar e pode simplesmente inspecionar o HTML renderizado em suas solicitações HTML simples. Compare isso à abordagem "magic div", usada por muitas outras bibliotecas de interface do usuário do AJAX, muitas vezes contendo megabytes de JavaScript para criar seus DataGrids e TreeViews.

Assim, é possível compreender que o valor de 100 vezes mais velocidade e capacidade de resposta não é um exagero. Na verdade, em comparação com todos os kits de ferramentas de interface do usuário de componente, usados em combinação com C# e ASP.NET, ele é entre 100 e 250 vezes mais rápido e responsivo em relação ao consumo de largura de banda. Recentemente, fiz uma medição de desempenho entre o widget TreeView do AJAX gerenciado no System42 e três dos maiores kits de ferramentas de componente na pilha do ASP.NET. Descobri que a diferença no consumo de largura de banda era algo entre 150 e 220 mais rápido e mais responsivo.

Para ilustrar o que isso implica, imagine que você está usando uma conexão com a Internet extremamente lenta, em que leva um segundo para baixar 5 KB de JavaScript. Isso implica um segundo para baixar o JavaScript AJAX gerenciado e possivelmente algo perto de três minutos e 40 segundos para baixar as partes em JavaScript de alguns dos outros kits de ferramentas. É desnecessário dizer quão significativa a diferença seria com relação à conversão se você criasse duas soluções de comércio eletrônico com essas duas abordagens.

Mostre-me o código

OK, chega de conversa, é hora de colocar a mão na massa. Primeiro, baixe o Phosphorus Five em bit.ly/2u5W0EO. Em seguida, abra o arquivo p5.sln e compile o Phosphorus Five, de modo que você possa chegar ao seu assembly p5.ajax.dll. Você consumirá o p5.ajax.dll em seu aplicativo Web como uma referência, então você precisará compilá-lo antes de prosseguir. Observe que o Phosphorus Five consiste de mais de 30 projetos, mas neste artigo, estou me concentrando no projeto p5.ajax.

Em seguida, crie um site da Web do ASP.NET no Visual Studio. Verifique se você criou um aplicativo Web Forms. No Visual Studio para Mac, você pode localizar isso em Arquivo | Nova Solução | Outro | .NET | Projeto Web Forms ASP.NET.

Crie uma referência dentro de seu site da Web recém-criado para o assembly p5.ajax.dll já compilado e modifique o web.config para que se assemelhe ao seguinte código:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <pages clientIDMode="Static">
      <controls>
        <add assembly="p5.ajax" namespace="p5.ajax.widgets" tagPrefix="p5" />
      </controls>
    </pages>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
</configuration>

As peças importantes nesse código são o "clientIDMode" e o "add assembly." Nesse ponto, você pode usar qualquer um dos controles p5.ajax de dentro da sua marcação .aspx prefixando-os com p5. Verifique se você modificou o conteúdo da página Default.aspx para que se assemelhe ao código na Figura 1.

Figura 1 Criando uma página com um único botão que altera seu texto quando clicado

<%@ Page Language="C#" Inherits="foobar.Default" %>
<!DOCTYPE html>
<html>
<head runat="server">
  <title>Default</title>
</head>
<body>
  <form id="form1" runat="server">
    <p5:Literal 
      runat="server"
      id="foo"
      onclick="foo_onclick"
      Element="button">Click me!</p5:Literal>
  </form>
</body>
</html>

Em seguida, altere seu codebehind para o seguinte:

using System;
namespace foobar
{
  public partial class Default : p5.ajax.core.AjaxPage
  {
    [p5.ajax.core.WebMethod]
    public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      sender.innerValue = "Hello World from Managed Ajax!";
    }
  }
}

Observe que você precisa primeiro herdar sua página de AjaxPage, adicionar um atributo WebMethod para o manipulador de eventos e definir o primeiro parâmetro do seu manipulador de eventos com um tipo forte, especificamente como um widget "Literal". Nesse ponto, você pode iniciar seu site da Web, clicar no botão e desfrutar do resultado. Se você obtiver bugs estranhos ao depurar seu site da Web, verifique se você desligou as configurações de "link do navegador" para o Visual Studio, que normalmente são um botão de barra de ferramentas, na parte superior do Visual Studio. Se você está curioso sobre o que acontece aqui, tente inspecionar suas solicitações HTTP. Além disso, não deixe de conferir seu HTML inicial.

Uau, o que foi isso?

Isso foi o AJAX gerenciado na prática. Há vários pontos importantes nessa ideia que devem ser considerados. Primeiro, você pode modificar qualquer propriedade em qualquer controle de sua página de qualquer manipulador de eventos do AJAX em sua página. Se você criou outro widget Literal, por exemplo, um "Element" tipo "p", você poderia atualizar seu conteúdo do manipulador de eventos "foo_onclick" de seu botão.

Segundo, você pode adicionar, remover, atualizar ou recuperar dinamicamente qualquer propriedade do seu widget de qualquer maneira que considere adequada. Para referenciar qualquer atributo ou manipulador de eventos, apenas use o operador subscrito do C#. Na Figura 2, em vez de configurar o innerValue do widget, sua propriedade de estilo é marcada e alterna para uma tela de fundo amarela, usando a propriedade de estilo CSS. Observe como ela é capaz de persistir e "lembrar" da propriedade de estilo do widget. Observe também que isso é feito sem passar grandes quantidades de ViewState em ida e volta entre o cliente e o servidor.

Em um aplicativo do mundo real, provavelmente é melhor usar classes CSS, o que poderia ser feito trocando a referência na Figura 2 de "style" para "class". Mas eu queria manter este exemplo simples, então não misturei arquivos CSS aqui, optando por em vez disso usar o atributo style por questão de conveniência. Usando a abordagem mostrada na Figura 2, você poderia adicionar, remover e alterar qualquer atributo que desejar, em qualquer widget em sua página.

Figura 2 Alternando a cor da tela de fundo

using System;
namespace foobar
{
  public partial class Default : p5.ajax.core.AjaxPage
  {
    [p5.ajax.core.WebMethod]
    public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      if (sender.HasAttribute ("style"))
        sender.DeleteAttribute ("style");
      else
        sender ["style"] = "background-color:Yellow;";
    }
  }
}

E o terceiro ponto – e provavelmente o mais importante – é que você pode adicionar, remover, atualizar e inserir dinamicamente qualquer novo controle AJAX em qualquer outro widget, conforme considerar adequado. Antes que você dê uma última olhada neste último ponto, no entanto, você precisará examinar a "trindade de widgets".

Há três widgets diferentes em p5.ajax, mas eles também são muito similares na API deles. Combinando esses três widgets juntos usando composição, você poderá criar qualquer marcação HTML que desejar. No exemplo na Figura 2, você usou o widget Literal. O widget Literal tem uma propriedade "innerValue" que, no lado do cliente, é mapeada para "innerHTML" e simplesmente permite que você altere o conteúdo dela como um pedaço de cadeia de caracteres ou de HTML.

O widget Container pode conter widgets. E ele se lembrará da coleção de controles dele e permitirá que você adicione, remova ou altere dinamicamente essa coleção durante solicitações AJAX.

O terceiro widget é o Void, que é exclusivamente usado para controles que não têm nenhum conteúdo, tais como elementos de entrada HTML, elementos br, elementos hr e assim por diante. O mais importante para este exemplo é provavelmente o widget Container. Prossiga e altere o código na página .aspx para o que você vê na Figura 3.

Figure 3 Criando uma página com um botão e uma lista com marcadores contendo um item de lista

<%@ Page Language="C#" Inherits="foobar.Default" %>
<!DOCTYPE html>
<html>
<head runat="server">
  <title>Default</title>
</head>
<body>
  <form id="form1" runat="server">
    <p5:Literal 
      runat="server"
      id="foo"
      onclick="foo_onclick"
      Element="button">Click me!</p5:Literal>
  <p5:Container
      runat="server"
      id="bar"
      Element="ul">
      <p5:Literal
        runat="server"
        id="initial"
        onclick="initial_onclick"
        Element="li">Initial list element, try clicking me!</p5:Literal>
  </p5:Container>
  </form>
</body>
</html>

A hierarquia de widgets na Figura 3 criará um "botão" e um elemento "ul" com um elemento filho "li". Em seguida, altere o código C# subjacente ao código na Figura 4.

Figura 4 Mapeando manipuladores de eventos AJAX para criar um novo item de lista

using System;

namespace foobar
{
  public partial class Default : p5.ajax.core.AjaxPage
  {
    protected p5.ajax.widgets.Container bar;

    [p5.ajax.core.WebMethod]
    public void foo_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      // Using the factory method to create a new child widget for our "ul" widget.
      var widget = bar.CreatePersistentControl<p5.ajax.widgets.Literal>();
      widget.Element = "li";
      widget.innerValue = "Try clicking me too!";

      // Notice we supply the name of the method below here.
      widget ["onclick"] = "secondary_onclick";
    }

    [p5.ajax.core.WebMethod]
    public void initial_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      sender.innerValue = "I was clicked!";
    }

    [p5.ajax.core.WebMethod]
    public void secondary_onclick(p5.ajax.widgets.Literal sender, EventArgs args)
    {
      sender.innerValue = "I was ALSO clicked!";
    }
  }
}

Perceba que o último pedaço de código injetou dinamicamente novos widgets no widget Container. Basicamente, os novos elementos "li" foram anexados ao elemento "ul" dinamicamente durante uma solicitação AJAX e isso simplesmente funcionou! Esses widgets também são persistentemente lembrados entre solicitações AJAX, de modo que você pode alterar as propriedades deles e invocar manipuladores de eventos para eles. Além disso, por meio da propriedade "Element", quaisquer elementos HTML podem ser renderizados e qualquer atributo pode ser adicionado por meio do operador subscrito.

Agora você tem um controle 100% perfeito sobre sua marcação HTML e você pode criar solicitações AJAX muito pequenas e respostas que atualizam qualquer coisa que você deseje atualizar em sua página, de qualquer modo que você considere adequado. E você fez isso com 4,8 KB de JavaScript. Você transformou o desenvolvimento AJAX de aplicativos Web em algo que pode ser feito tão facilmente quanto o desenvolvimento do bom e velho Windows Forms. E no processo, você acabou ficando com aplicativos Web 100 vezes mais rápidos e responsivos.

Um exercício em Hyperlambda

Alguns meses atrás escrevei um artigo na edição de junho de 2017 da MSDN Magazine intitulado “Make C# More Dynamic with Hyperlambda” (Tornar o C# Mais Dinâmico com Hyperlambda – msdn.com/magazine/mt809119), que explorava a linguagem de programação não tradicional Hyperlambda com suas raízes em árvores de execução. Trago isso à tona agora porque a abordagem baseada em árvore da Hyperlambda torna extremamente fácil declarar uma hierarquia de widgets AJAX. Combine p5.ajax com Hyperlambda para consumir um widget TreeView AJAX e algumas eficiências impressionantes surgirão.

Vamos explorar isso. Primeiro, além do Phosphorus Five, você precisa baixar o System42 e colocá-lo na pasta p5.webapp principal de acordo com as instruções em bit.ly/2vbkNpg. Então inicialize o System42, que contém um widget de modo de exibição de árvore AJAX ultrarrápido, abra "CMS," crie uma nova página lambda clicando em + e cole o código mostrado na Figura 5.

Figura 5 Criando um TreeView AJAX, que permitirá navegar pelas pastas no disco

create-widget
  parent:content
  widgets
    sys42.widgets.tree
      crawl:true
      items
        root:/
      .on-get-items
        list-folders:x:/../*/_item-id?value
        for-each:x:/@list-folders/*?name
          list-folders:x:/@_dp?value
          split:x:/@_dp?value
            =:/
          add:x:/../*/return/*
            src:@"{0}:{1}"
              :x:/@split/0/-?name
              :x:/@_dp?value
          if:x:/@list-folders/*
            not
            add:x:/../*/return/*/items/0/-
              src
                class:tree-leaf
        return
          items

Clique em configurações, escolha vazio como seu Modelo, clique em OK, salve sua página e clique em Exibir página.

Tente expandir o modo de exibição de árvore AJAX enquanto inspeciona o que é transmitido em suas solicitações HTTP e perceba que você acabou de criar, com 24 linhas de Hyperlambda, um modo de exibição de árvore AJAX para navegação de pastas que exibirá as pastas da pasta p5.webapp e cujo consumo de largura de banda inicial foi de apenas 10,9 KB!

Se comparar esses resultados com quaisquer outros kits de ferramentas AJAX, você muitas vezes descobrirá que outros kits de ferramentas exigem o download de muitos megabytes de JavaScript – além de outras coisas que são transmitidas – enquanto o TreeView Hyperlambda não ultrapassa 4,8 KB de JavaScript.

Esse modo de exibição de árvore AJAX foi compilado com um total de 717 linhas de código, em Hyperlambda puro, usando nada mais do que widgets de tipo Literal, Container e Void. A maior parte do código dele é composto de comentários, então aproximadamente 300 linhas de código são requeridas para criar o controle de exibição de árvore AJAX. O widget foi consumido com 24 linhas de Hyperlambda, o que permite que você navegue por suas pastas no disco. No entanto, seriam necessárias milhares de linhas de código para criar o controle com qualquer outra coisa e centenas de linhas para consumi-lo, do mesmo modo que foi feito com 24 linhas de código na Figura 5.

Se você desejasse, poderia agora trocar três linhas de código no exemplo Hyperlambda e ter como resultado seu próprio widget personalizado de Evento Ativo especializado, que permitiria que você consumisse seu widget especializado com uma única linha de código. Leia como fazer isso em bit.ly/2t96gsQ.

Agora você é capaz de criar um modo de exibição de árvore AJAX que navegará pelas pastas do seu servidor com uma linha de código. Criar algo equivalente em outros kits de ferramentas muitas vezes exigiria centenas de linhas de código em quatro linguagens de programação diferentes. Você fez isso com uma linha de código em uma linguagem de programação, com desempenho 300 vezes melhor que o da concorrência.

Conclusão

Imagine ser capaz de produzir resultados 100 vezes melhores, mais rápidos e otimizados, qualidade 100 vezes melhor com 100 vezes menos bugs e ser 100 vezes mais produtivo do que antes. Para ter certeza de que você está usando os produtos mais recentes, baixe o Phosphorus Five em bit.ly/2uwNv65 e o System42 em bit.ly/2vbkNpg.


Thomas Hansen desenvolve software desde os oito anos de idade, quando começou a escrever código usando um computador Oric-1 em 1982. De vez em quando, ele cria códigos que fazem mais bem do que mal. Suas paixões incluem a Web, o AJAX, metodologias Agile e arquitetura de software. Contate-o em thomas@gaiasoul.com.

Agradecemos aos seguintes especialistas técnicos da Microsoft pela revisão deste artigo: James McCaffrey


Discuta esse artigo no fórum do MSDN Magazine