Os 8 erros mais comuns que os desenvolvedores do Backbone.js cometem

Publicados: 2022-03-11

Backbone.js é uma estrutura minimalista que visa fornecer um conjunto simples de estruturas de dados e recursos que você pode usar para criar o front-end de uma aplicação web estruturada. Pronto para uso, os componentes do Backbone.js fornecem um ambiente intuitivo com o qual você já deve estar familiarizado ao trabalhar com modelos e visualizações no back-end. Modelos e coleções em Backbone.js são simples, mas vêm com alguns recursos muito úteis, como a opção de integrá-los facilmente com APIs REST JSON. Mas eles também são flexíveis o suficiente para serem adaptados a praticamente qualquer uso prático.

Neste tutorial do Backbone.js, vamos dar uma olhada em alguns erros comuns que são frequentemente cometidos por desenvolvedores freelancers que tentam aprender o Backbone.js pela primeira vez e maneiras de evitá-los.

Erro nº 1: ignorar as funcionalidades do arsenal do Backbone.js

O Backbone.js pode ser uma estrutura minimalista, mas (junto com o Underscore.js) fornece uma infinidade de recursos e funcionalidades que podem cobrir facilmente as necessidades mais básicas e algumas das necessidades críticas que surgem ao desenvolver um aplicativo da Web moderno. Um erro comum que os desenvolvedores iniciantes costumam cometer é que eles consideram o Backbone.js mais uma estrutura de cliente semelhante ao MVC para a web. Embora esta seção fale sobre algo muito óbvio, quando se trata de Backbone.js é um erro realmente crítico não explorar o framework completamente. A estrutura pode ser pequena em tamanho, mas é isso que a torna uma ótima candidata para essa exploração completa. Especialmente seu código-fonte pequeno e bem anotado.

O Backbone.js fornece o mínimo necessário para fornecer ao seu aplicativo da Web a estrutura da qual ele pode se beneficiar. Com sua extensibilidade e abundância de plugins, o aprendizado do Backbone.js pode ser usado para construir alguns aplicativos da web incríveis. Alguns dos recursos mais óbvios do Backbone.js são expostos por meio de modelos, coleções e visualizações. Os componentes do roteador e do histórico fornecem um mecanismo simples e elegante para oferecer suporte ao roteamento do lado do cliente. Embora o Underscore.js seja uma dependência do Backbone.js, ele está muito bem integrado ao framework, já que modelos e coleções se beneficiam muito desse incrível cinto de utilidades para JavaScript e também está disponível à sua disposição.

O código-fonte do framework é tão bem escrito e anotado que provavelmente seria possível ler tudo enquanto tomava uma xícara de café. Iniciantes podem se beneficiar muito lendo as anotações de origem, pois podem aprender muito sobre como a estrutura funciona internamente e também adotar um conjunto de boas práticas quando se trata de JavaScript.

Erro nº 2: Modificando o DOM em resposta direta a eventos arbitrários

Algo que tendemos a fazer quando começamos a aprender o Backbone.js é não fazer as coisas conforme recomendado pelo Backbone.js. Por exemplo, tendemos a lidar com eventos e visualizar atualizações da mesma forma que faríamos com jQuery em sites simples. O Backbone.js destina-se a fornecer ao seu aplicativo da Web uma estrutura rígida por meio da separação adequada de interesses. O que costumamos fazer com o Backbone.js é atualizar uma visualização em resposta a eventos DOM arbitrários:

 var AudioPlayerControls = Backbone.View.extend({ events: { 'click .btn-play, .btn-pause': function(event) { $(event.target).toggleClass('btn-play btn-pause') } }, // ... })

Isso é algo que deve ser evitado a todo custo. Pode ser possível apresentar exemplos obscuros onde isso possa fazer sentido; mas na maioria dos casos, existem maneiras muito melhores de fazer isso. Na verdade, uma maneira que eu poderia exemplificar aqui é usar o modelo para rastrear o estado do player de áudio e usar essas informações de estado para renderizar o botão (ou mais especificamente seus nomes de classe):

 var AudioPlayerControls = Backbone.View.extend({ events: { 'click .btn-play, .btn-pause': function(event) { this.model.set('playing', !this.model.get('playing')) } }, initialize: function() { this.listenTo(this.model, 'change', this.render) this.render() }, // ... })
 <button class=”btn btn-<%- playing ? 'pause' : 'play' %>”></button>

Pode haver raras situações em que a manipulação direta do DOM dos manipuladores de eventos fará sentido, mas o custo envolvido no gerenciamento de manipulações complexas do DOM dos manipuladores de eventos quase nunca vale a pena. Isso é algo que o Backbone.js visa resolver. Usar o Backbone.js para fazer algo assim é um erro.

Erro nº 3: subestimar o custo de renderização

Como o Backbone.js facilita muito a renderização e a rerenderização do DOM à vontade ou em resposta a eventos, geralmente ignoramos o impacto que isso causa no desempenho geral do aplicativo da web. Existem muitas maneiras de acabarmos com o método de renderização em nossas visualizações. Muitas vezes, isso pode não parecer muito, pois os navegadores da Web modernos estão se tornando softwares de alto desempenho. Mas à medida que o aplicativo da Web cresce e a quantidade de dados com os quais ele lida cresce, a queda no desempenho se torna cada vez mais aparente.

Podemos ver isso em ação por meio de um exemplo artificial em que começamos com uma pequena coleção de modelos e a renderizamos em uma exibição de lista:

 var AudioPlayerPlaylist = Backbone.View.extend({ template: _.template('<ul> <% _.each(musics, function(m) { %> <li><%- m.title %></li> <% }) %> </ul>'), initialize: function() { this.listenTo(this.collection, 'add', this.render) }, // ... })

Neste exemplo do Backbone.js, estamos renderizando novamente sempre que um modelo é adicionado à coleção. Isso funcionará bem. No entanto, como o evento “add” é acionado toda vez que um modelo é adicionado à lista, imagine buscar uma grande lista de modelos do servidor. O método render será invocado várias vezes consecutivas, uma vez para cada modelo na resposta do servidor. Um modelo suficientemente grande será suficiente para fazer seu aplicativo gaguejar e arruinar a experiência do usuário. Às vezes, uma pequena resposta é suficiente, dependendo da complexidade da exibição que está sendo renderizada.

Uma solução muito rápida para isso é simplesmente não chamar o método render para cada modelo que está sendo adicionado. Em situações como essas, os modelos serão adicionados em lote, e você pode realmente fazer algo para que o método de renderização seja acionado apenas quando ele for invocado, mas não invocado novamente dentro de um período de tempo especificado. A dependência do Backbone.js Underscore.js vem com uma função útil útil para isso: “_.debounce”. Tudo o que você precisa para tirar proveito disso é alterar a linha JavaScript de vinculação de eventos com isso:

 this.listenTo(this.collection, 'add', _.debounce(_.bind(this.render), 128))

Isso fará com que o retorno de chamada do evento seja acionado toda vez que o evento “add” acontecer, no entanto, ele aguardará 128 milissegundos do último evento antes de realmente invocar o método render.

Na maioria dos casos, isso será considerado uma solução rápida. Na verdade, existem maneiras mais apropriadas de evitar o thrashing de renderização. Os desenvolvedores por trás do Trello uma vez escreveram um post no blog discutindo sobre sua experiência e abordagem para melhorar o desempenho de renderização ao usar o Backbone.js.

Erro nº 4: deixar os ouvintes de eventos vinculados além de seu uso

Deixar os ouvintes de eventos não utilizados vinculados provavelmente é algo que pode acontecer independentemente de qual estrutura JavaScript você usa ou se você usa uma. Embora o Backbone.js facilite evitar esse problema, certamente é um erro ainda deixar brechas em potencial para vazamentos de memória fáceis em seu aplicativo da web. O componente “Event” do Backbone.js é certamente uma implementação bem legal. Ele permite que objetos JavaScript implementem facilmente recursos baseados em eventos. Como as visualizações são onde a maior parte do nosso consumo de eventos geralmente acontece, é fácil cometer esse erro:

 var AudioPlayerControl = Backbone.View.extend({ initialize: function() { this.model.on('change', _.bind(this.render, this)) // ... }, // ... })

A linha de ligação de evento neste trecho de código não é muito diferente da do primeiro exemplo. Tudo o que fizemos aqui foi alterar “this.listenTo(this.model, …)” para “this.model.on(…)”. Como estamos muito acostumados com a chamada “.on()” para vinculação de eventos de nossa experiência com alguns outros frameworks e bibliotecas JavaScript, quando começamos a usar o Backbone.js, geralmente tendemos a usar as chamadas “.on()” para vincular eventos. Isso teria sido bom, apenas se nos importássemos em chamar “.off()” para desvincular os manipuladores de eventos quando eles não forem mais necessários. Mas raramente fazemos isso e acaba sendo uma fonte de vazamentos de memória.

O Backbone.js oferece uma maneira simples de resolver esse problema. É através do uso do método “object.listenTo()”. Isso permite que o objeto que você está chamando “listenTo()” acompanhe quais eventos ele está ouvindo e também facilita a desvinculação de todos esses eventos de uma só vez. As visualizações, por exemplo, param automaticamente de ouvir todos os eventos vinculados assim que você chama “remove()” nele.

Erro nº 5: Criando visualizações monolíticas

Se você pensar bem, o minimalismo do Backbone.js oferece uma tremenda flexibilidade para como você deseja arquitetar o front-end do seu aplicativo da web. Com modelos, coleções e visualizações sendo os blocos de construção de seus componentes, é essencial mantê-los o mais leves e específicos possível. Na maioria das vezes, são as visualizações que acabam se tornando o aspecto mais pesado do seu aplicativo da Web em termos de código. Mas é muito importante que você não acabe criando visões monolíticas gigantescas que acabem tentando fazer tudo o que seu aplicativo tem a oferecer. Em vez de fazer uma visualização gigante de “AudioPlayer” com toda a lógica amontoada nela, divida-a em várias visualizações lógicas, como uma visualização para a lista de reprodução, uma visualização para os controles, uma visualização para o visualizador e assim por diante. O tipo de granularidade que você deseja garantir provavelmente depende do aplicativo que você está tentando construir.

Isso ocorre porque, com visualizações granulares, em que cada visualização faz algo específico e certo, desenvolver um aplicativo da Web com o Backbone.js se torna muito fácil. Seu código deve ser mais sustentável e fácil de estender ou modificar no futuro. Depois, há o outro extremo, onde você acaba exagerando. As visualizações do Backbone.js são projetadas para facilitar o trabalho com um modelo ou uma coleção, e isso provavelmente pode funcionar como uma dica de como você deve estruturar seu aplicativo. Ian Storm Taylor compartilhou algumas ideias valiosas em seu blog que você provavelmente deve ter em mente ao implementar visualizações.

Erro nº 6: não perceber que o Backbone.js pode ser adaptado a APIs não RESTful

O Backbone.js funciona com APIs RESTful baseadas em JSON prontas para uso. Tudo o que você precisa para isso é jQuery (ou algo que seja um substituto imediato para ele, como Zepto). No entanto, o Backbone.js é extremamente extensível. Na verdade, o Backbone.js pode ser adaptado para usar outros tipos de APIs e até mesmo outros tipos de formatos de codificação.

O componente do Backbone.js que trata da interação do front-end com os serviços de back-end é o “Sync”. Esse componente expõe vários atributos que você pode substituir facilmente para personalizar a maneira de interação do Backbone.js com os endpoints da API. Na verdade, também é possível substituir o mecanismo de sincronização padrão por algo não tão tradicional para dizer o mínimo, como usar localStorage para persistir dados, em vez de serviços de back-end.

Existem vários plugins que facilitam a personalização do comportamento de sincronização do Backbone.js. Por exemplo, um plugin chamado Backbone.dualStorage permite que você use os serviços de back-end e localStorage para manter os dados. Quando seu aplicativo fica offline, o plug-in usa localStorage para continuar atendendo solicitações de dados em cache e rastrear alterações que você pode sincronizar com o servidor posteriormente quando estiver online.

Embora o uso do Backbone.js com um back-end projetado para ser RESTful e compatível com ele seja mais fácil de usar, isso não significa que o Backbone.js é tudo com o qual o Backbone.js pode trabalhar. Com algumas alterações no mecanismo de sincronização padrão do Backbone.js, você pode adaptá-lo a uma ampla variedade de APIs de serviço de back-end e formatos de codificação.

Vale a pena mencionar que outras partes do Backbone.js também são flexíveis e, de certa forma, opcionais. Por exemplo, você não precisa usar o mecanismo de modelagem padrão que vem com o Underscore.js. Você nem precisa usar o componente de visualização do Backbone.js e pode substituí-lo por algo totalmente diferente, se desejar.

Erro nº 7: Armazenar dados em visualizações em vez de em modelos

Um erro que muitas vezes cometemos como iniciantes no aprendizado do Backbone.js é armazenar dados diretamente nas visualizações como atributos. Esses dados podem estar lá para rastrear algum estado ou alguma seleção do usuário. Isso é algo que deve ser evitado.

 var AudioPlayerVisualizer = Backbone.View.extend({ events: { 'click .btn-color': function(event) { this.colorHex = $(event.target).data('color-hex') this.render() } }, // ... })

Você sempre pode criar alguns modelos e coleções adicionais sem endpoints. Eles podem ajudá-lo a armazenar dados que não precisam necessariamente ser persistidos no back-end ou podem ser de natureza temporária. Armazená-los em modelos oferece o benefício de poder ouvir as mudanças. A visão relevante, ou mesmo múltiplas visualizações, podem observar esses modelos e se renderizar conforme necessário.

Imagine se você realmente armazenasse variáveis ​​de rastreamento de estado nas visualizações e tivesse que chamar o método de renderização toda vez que as alterasse. A falta de apenas uma chamada para esse método de renderização pode deixar seu aplicativo em um estado quebrado, em termos do que o usuário está experimentando na tela. Além disso, com visualizações pequenas, você pode precisar sincronizar essas variáveis ​​de estado em vários objetos de visualização e, em seguida, chamar o método de renderização neles também.

Erro #8: Usando jQuery “.on()” em vez de eventos delegados

O Backbone.js tem, na minha opinião, uma maneira magnífica de lidar com eventos DOM. Não usá-lo apresenta um monte de desvantagens. A função de ligação de evento “.on()” do jQuery pode parecer conveniente, mas muitas vezes acaba sendo um incômodo a longo prazo. Por exemplo, quando os elementos são desanexados do DOM, o jQuery automaticamente descarta todos os manipuladores de eventos vinculados aos elementos usando “.on()”. Isso significa que qualquer evento DOM que você tentar vincular de dentro de uma exibição precisará ser religado se você desvincular o elemento raiz do DOM e reanexá-lo.

 var AudioPlayerControls = Backbone.View.extend({ events: { 'click .btn-play, .btn-pause': function() { /* ... */ }, 'click .btn-prev': function() { /* ... */ }, 'click .btn-next': function() { /* ... */ }, 'click .btn-shuffle': function() { /* ... */ }, 'click .btn-repeat': function() { /* ... */ } }, // ... })

Quando o elemento correspondente a esta visão é reanexado ao DOM, tudo o que você precisa fazer é chamar “delegateEvents()” na visão para vincular todos esses eventos.

Observe que é importante entender como esses eventos são vinculados. Em vez de vincular o evento aos elementos especificados pelo seletor, o Backbone.js vincula o manipulador de eventos ao elemento raiz da exibição. Isso funciona bem em quase todos os casos e, de fato, funciona melhor para a maioria das nossas necessidades. Alterar ou substituir os elementos filho na subárvore DOM da exibição não exige que o Backbone.js vincule cada evento novamente aos novos elementos. Os ouvintes existentes continuam trabalhando.

No entanto, isso impede que determinados eventos sejam ouvidos. Um exemplo é onde você pode querer ouvir eventos de rolagem na “janela” ou em um elemento rolável filho. No caso de elementos filhos, você pode criar uma sub-visualização para esse elemento e manipular os eventos lá.

Conclusão

O Backbone.js, por ser um framework muito compacto e extensível, é uma excelente opção para aplicativos da Web que exigem muita flexibilidade nos bastidores. Ao contrário de frameworks como Angular.js e Ember.js que estão sempre lá para lhe dizer como fazer o que você quer fazer, o Backbone.js dá um passo atrás, oferece um conjunto poderoso de ferramentas e permite que você decida como usar eles. Espero que este tutorial do Backbone.js para iniciantes o ajude a evitar alguns dos erros comuns de desenvolvimento e a construir algo incrível com ele.