Na construção de web sites ou sistemas webs, procuramos sempre a melhor solução que atenda aos requisitos do projeto.
A internet só cresce, cada vez mais pessoas estão acessando sites/sistemas web.
Diante de tantos dispositivos acessando a internet, a performance de web sites tornam-se cada vez mais importante. Um exemplo simples que pode levar a sua aplicação a ter uma queda de desempenho, é a quantidade de dados que precisamos apresentar para nossos usuários.
Uma das soluções para sanar essa questão, é procurar trabalhar com uma quantidade de dados menor sempre que possível. Esta ação nos permite trafegar uma quantidade menor de dados na rede.
Quando há muitos registros na base de dados, procuramos exibir uma pequena parte do todo, isso tem um ganho no processamento de I/O. A requisição tende a ser mais rápida. Uma solução muito abordada no mercado, é a paginação de dados, na qual buscamos uma quantidade x de informações e a exibimos.
Mas essa solução pode ser melhorada, requisições assíncronas em formato Json tornam-se mais rápida por trafegarem o dado de forma mais “bruta”. A paginação por demanda utilizando os recursos do JavaScript, é uma das formas para melhorar uma solução amplamente utilizada no mercado.
Logo a seguir, veremos como utilizar o poder dos recursos do JavaScript com paginação por demanda.
HTML
<div class="row"> <section class="form-group"> <table class="table table-hover table-responsive table-bordered" data-bind="visible:Produtos().length > 0"> <thead> <tr> <th>Descrição</th> <th>Quantidade</th> <th>Preço</th> </tr> </thead> <tbody data-bind="foreach: Produtos"> <tr> <td data-bind="text: DescricaoProduto"></td> <td data-bind="text: Quantidade"></td> <td data-bind="text: Preco"></td> </tr> </tbody> </table> <nav class="text-center nav-pagination-marca"> <ul id="pagination"></ul> </nav> </section> </div>
JavaScript
Nesse exemplo, foi utilizado o framework Knockoutjs para renderizar o HTML com os dados. A API de paginação utilizada foi a twbs-pagination. Esse plugin está disponível no nuget para ser baixado e usado.
Lembrando que pode ser qualquer framework como o AngularJs, ReactiveJs e entre outros.
function AppViewModel() { var NumeroLinhasPorPagina = 10; var self = this; self.Produtos = ko.observableArray([]); $.ajax({ type: "GET", url: "/Home/index", dataType: "json", async: true, data: { 'linhasPorPagina': NumeroLinhasPorPagina, "pagina": 1 }, success: function (data) { self.Produtos(data); Pagination(data[0].TotalPage, NumeroLinhasPorPagina); } }); function Pagination(NumeroLinhasEncontradas, NumeroLinhasPorPagina) { $("#PaginationLink").html(''); $("#PaginationLink").html('<ul id="pagination"></ul>'); $('#pagination') .twbsPagination({ totalPages: Math.ceil(NumeroLinhasEncontradas / NumeroLinhasPorPagina), initiateStartPageClick: false, startPage: 1, visiblePages: 5, href: false, hrefVariable: '{{number}}', first: '««', prev: '«', next: '»', last: '»»', loop: false, paginationClass: 'pagination pagination-lg', nextClass: 'next', prevClass: 'prev', lastClass: 'last', firstClass: 'first', pageClass: 'page', activeClass: 'active', disabledClass: 'disabled', onPageClick: function (event, page) { $.ajax({ type: 'GET', url: "/Home/index", dataType: "json", async: true, data: { 'linhasPorPagina': NumeroLinhasPorPagina , "pagina": page }, success: function (data) { self.Produtos(data); } }); }, }); }; }; var vm = new AppViewModel(); ko.applyBindings(vm);
Aqui temos o tempo do primeiro request. Neste primeiro momento, é preciso executar duas requisições, a primeira, caso não esteja usando single page, fará uma requisição normal. Vai carregar o HTML e todas as bibliotecas necessárias.
No segundo momento, estamos navegando entre as páginas apresentadas na tela. O tempo de resposta tende a ser menor do que uma requisição normal.
Lembrando que a consulta na base de dado deve esta paginada também. Nesse link você encontrará um artigo que fala a respeito dos ganhos na paginação na base de dados.
Aqui temos a consulta utilizada para acessar a base de dados.
C# Repositorie
using Dapper; using ProjetoPaginationAjax.MVC.Models.Interfaces; using System.Collections.Generic; using System.Linq; namespace ProjetoPaginationAjax.MVC.Models { public class PaginationService : GetConnectionDapper, IProduto { public IEnumerable<Produto> BuscarTodosProdutosPorDemanda( int linhasPorPagina, int pagina) { var sql = @"SELECT IdProduto, DescricaoProduto, Quantidade, Preco , StatusProduto , COUNT(IdProduto) over() as TotalPage FROM Produto ORDER BY DescricaoProduto OFFSET ((@pagina - 1) * @linhasPorPagina) ROWS FETCH NEXT @linhasPorPagina ROWS ONLY"; using (var conn = Connection) { conn.Open(); return conn.Query<Produto>(sql, new { pagina = pagina, linhasPorPagina = linhasPorPagina }).ToList(); } } } }
E o nosso controller que faz o acesso ao método de paginação.
C# Controller
using ProjetoPaginationAjax.MVC.Models; using System.Web.Mvc; namespace ProjetoPaginationAjax.MVC.Controllers { public class HomeController : Controller { public ActionResult Index(int? linhasPorPagina, int? pagina) { if (Request.IsAjaxRequest()) { var produtos = new PaginationService(); var resultado = produtos.BuscarTodosProdutosPorDemanda( (linhasPorPagina ?? 10), (pagina ?? 1) ); return Json(resultado, JsonRequestBehavior.AllowGet); } return View(); } } }
Conclusão
A paginação de registro garante um trafego menor nas requisições, contudo é preciso sempre analisar o contexto do projeto ao qual estamos inseridos. Essa prática é muito bem-vinda desde que ela seja necessária.
(Cross-post de – http://adeildo.azurewebsites.net/)
Adeildo Oliveira