8 самых распространенных ошибок, которые допускают разработчики Backbone.js

Опубликовано: 2022-03-11

Backbone.js — это минималистичный фреймворк, целью которого является предоставление простого набора структур данных и функций, которые можно использовать для создания структурированного внешнего интерфейса веб-приложения. Стандартные компоненты Backbone.js предоставляют интуитивно понятную среду, с которой вы, возможно, уже знакомы при работе с моделями и представлениями на серверной части. Модели и коллекции в Backbone.js просты, но они обладают некоторыми очень полезными функциями, такими как возможность простой интеграции их с REST JSON API. Но они также достаточно гибки, чтобы их можно было адаптировать практически для любого практического использования.

В этом руководстве по Backbone.js мы рассмотрим некоторые распространенные ошибки, которые часто совершают внештатные разработчики, впервые пробующие изучение Backbone.js, и способы их избежать.

Ошибка №1: Игнорирование арсенала функций Backbone.js

Backbone.js может быть минималистским фреймворком, но он (наряду с Underscore.js) предоставляет множество функций и функций, которые могут легко удовлетворить самые основные и некоторые критические потребности, возникающие при разработке современного веб-приложения. Одна из распространенных ошибок, которую часто совершают начинающие разработчики, заключается в том, что они считают Backbone.js еще одним клиентским фреймворком, похожим на MVC, для Интернета. Хотя в этом разделе говорится о чем-то очень очевидном, когда дело доходит до Backbone.js, не изучить фреймворк полностью — это действительно серьезная ошибка. Фреймворк может быть небольшим по размеру, но именно это делает его отличным кандидатом для тщательного исследования. Особенно его небольшой и красиво аннотированный исходный код.

Backbone.js предоставляет необходимый минимум, чтобы дать вашему веб-приложению структуру, от которой оно может извлечь выгоду. Благодаря расширяемости и множеству плагинов изучение Backbone.js может быть использовано для создания потрясающих веб-приложений. Некоторые из наиболее очевидных функций Backbone.js раскрываются через модели, коллекции и представления. Компоненты маршрутизатора и истории предоставляют простой, но элегантный механизм для поддержки маршрутизации на стороне клиента. Хотя Underscore.js является зависимостью от Backbone.js, он довольно хорошо интегрирован в фреймворк, так как модели и коллекции получают большую пользу от этого удивительного пояса утилит для JavaScript, который также доступен в вашем распоряжении.

Исходный код фреймворка настолько хорошо написан и аннотирован, что его можно было бы прочесть за чашечкой кофе. Начинающие могут извлечь большую пользу из чтения исходных аннотаций, так как они могут многое узнать о внутренней работе фреймворка, а также принять аккуратный набор лучших практик, когда дело доходит до JavaScript.

Ошибка № 2: модификация DOM в прямом ответе на произвольные события

Когда мы только начинаем изучать Backbone.js, мы склонны делать то, что не рекомендуется делать в соответствии с рекомендациями Backbone.js. Например, мы склонны обрабатывать события и просматривать обновления так же, как с jQuery на простых веб-сайтах. Backbone.js предназначен для того, чтобы дать вашему веб-приложению жесткую структуру за счет надлежащего разделения задач. Что мы часто делаем с Backbone.js, так это обновляем представление в ответ на произвольные события DOM:

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

Это то, чего следует избегать любой ценой. Можно привести неясные примеры, где это может иметь смысл; но в большинстве случаев есть гораздо лучшие способы сделать это. На самом деле, один из способов, который я мог бы проиллюстрировать здесь, — это использовать модель для отслеживания состояния аудиоплеера и использовать эту информацию о состоянии для отображения кнопки (или, точнее, имен ее классов):

 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>

Могут быть редкие ситуации, когда прямое манипулирование DOM из обработчиков событий имеет смысл, но затраты, связанные с управлением сложными манипуляциями с DOM из обработчиков событий, почти никогда не оправдывают себя. Это то, что Backbone.js стремится решить. Использовать Backbone.js для чего-то подобного — ошибка.

Ошибка №3: ​​недооценка стоимости рендеринга

Поскольку Backbone.js позволяет очень легко отображать и повторно отображать DOM по желанию или в ответ на события, мы часто упускаем из виду, какое влияние это оказывает на общую производительность веб-приложения. Есть много способов, которыми мы можем в конечном итоге перебить метод рендеринга в наших представлениях. Часто это может показаться не таким уж большим, поскольку современные веб-браузеры становятся высокопроизводительными программами. Но по мере роста веб-приложения и роста объема данных, с которыми оно работает, падение производительности становится все более и более очевидным.

Мы можем увидеть это в действии на надуманном примере, где мы начинаем с небольшой коллекции моделей и визуализируем ее в виде списка:

 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) }, // ... })

В этом примере Backbone.js мы повторно отображаем каждый раз, когда модель добавляется в коллекцию. Это будет работать нормально. Однако, поскольку событие «добавить» запускается каждый раз, когда модель добавляется в список, представьте себе получение большого списка моделей с сервера. Метод рендеринга будет вызываться несколько раз подряд, по одному разу для каждой модели в ответе сервера. Достаточно большой модели будет достаточно, чтобы ваше приложение заикалось и испортило взаимодействие с пользователем. Иногда достаточно небольшого отклика, в зависимости от сложности визуализируемого представления.

Очень быстрое решение этой проблемы — просто не вызывать метод рендеринга для каждой добавляемой модели. В подобных ситуациях модели будут добавляться в пакетном режиме, и вы действительно можете что-то сделать, чтобы метод рендеринга срабатывал только тогда, когда он вызывается, но не вызывается повторно в течение заданного периода времени. Зависимость Backbone.js Underscore.js поставляется с удобной служебной функцией для этого: «_.debounce». Все, что вам нужно, чтобы воспользоваться этим, — изменить строку JavaScript привязки события следующим образом:

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

Это приведет к тому, что обратный вызов события будет запускаться каждый раз, когда происходит событие «добавить», однако он будет ждать 128 миллисекунд с момента последнего события, прежде чем фактически вызовет метод рендеринга.

В большинстве случаев это будет рассматриваться как быстрое решение. На самом деле, есть более подходящие способы избежать пробуксовки рендеринга. Разработчики Trello однажды написали сообщение в блоге, в котором рассказали о своем опыте и подходе к повышению производительности рендеринга при использовании Backbone.js.

Ошибка № 4: Оставлять слушателей событий связанными за пределами их использования

Оставление неиспользуемых прослушивателей событий связанными, вероятно, может произойти независимо от того, какой JavaScript-фреймворк вы используете или используете ли вы его вообще. Несмотря на то, что Backbone.js позволяет легко избежать этой проблемы, безусловно, будет ошибкой оставлять потенциальные дыры для легкой утечки памяти в вашем веб-приложении. Компонент «Событие» Backbone.js, безусловно, является довольно аккуратной реализацией. Это позволяет объектам JavaScript легко реализовывать функции, основанные на событиях. Поскольку представления — это то место, где обычно происходит большая часть нашего потребления событий, здесь легко сделать эту ошибку:

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

Строка привязки события в этом фрагменте кода не сильно отличается от строки в первом примере. Все, что мы здесь сделали, это изменили «this.listenTo(this.model,…)» на «this.model.on(…)». Поскольку мы очень привыкли к вызову «.on()» для привязки событий из нашего опыта работы с некоторыми другими средами и библиотеками JavaScript, когда мы начинаем использовать Backbone.js, мы часто склонны использовать вызовы «.on()» для привязки. Мероприятия. Это было бы хорошо, только если бы мы вызывали «.off()», чтобы отвязать обработчики событий, когда они больше не нужны. Но мы редко так делаем, и в итоге это становится источником утечек памяти.

Backbone.js предлагает простой способ решить эту проблему. Это делается с помощью метода «object.listenTo()». Это позволяет объекту, для которого вы вызываете «listenTo()», отслеживать, какие события он прослушивает, а также упрощает развязку всех этих событий одновременно. Представления, например, автоматически перестают прослушивать все связанные события, как только вы вызываете для них «remove()».

Ошибка № 5: создание монолитных представлений

Если подумать, минимализм Backbone.js обеспечивает огромную гибкость в том, как вы хотите спроектировать внешний интерфейс вашего веб-приложения. Поскольку модели, коллекции и представления являются строительными блоками ваших компонентов, важно, чтобы они были как можно более легкими и конкретными. Чаще всего именно представления становятся самым тяжелым аспектом вашего веб-приложения с точки зрения кода. Но очень важно, чтобы вы не создавали гигантские монолитные представления, пытающиеся сделать все, что может предложить ваше приложение. Вместо создания гигантского представления AudioPlayer со всей логикой, втиснутой в него, разделите его на несколько логических представлений, таких как представление для списка воспроизведения, представление для элементов управления, представление для визуализатора и так далее. Степень детализации, которую вы хотите обеспечить, вероятно, зависит от приложения, которое вы пытаетесь создать.

Это связано с тем, что с детализированными представлениями, где каждое представление делает что-то конкретное и делает это правильно, разработка веб-приложения с помощью Backbone.js становится легкой задачей. Ваш код должен быть более удобным в сопровождении и простым для расширения или изменения в будущем. Но есть и другая крайность, когда вы в конечном итоге переусердствуете. Представления Backbone.js предназначены для того, чтобы вам было удобно работать с моделью или коллекцией, и это, вероятно, может служить подсказкой о том, как вы должны структурировать свое приложение. Ян Сторм Тейлор (Ian Storm Taylor) поделился в своем блоге некоторыми ценными идеями, которые вам, вероятно, следует иметь в виду при реализации представлений.

Ошибка № 6: Непонимание того, что Backbone.js можно адаптировать к не-RESTful API

Backbone.js работает с RESTful API на основе JSON «из коробки». Все, что вам нужно для этого, это jQuery (или что-то, что может заменить его, например, Zepto). Однако Backbone.js чрезвычайно расширяем. Фактически, Backbone.js можно адаптировать для использования других типов API и даже других типов форматов кодирования.

Компонент Backbone.js, который занимается взаимодействием внешнего интерфейса с внутренними службами, называется «Синхронизация». Этот компонент предоставляет ряд атрибутов, которые вы можете легко переопределить, чтобы настроить способ взаимодействия Backbone.js с конечными точками API. На самом деле, также можно заменить механизм синхронизации по умолчанию на что-то, мягко говоря, не совсем традиционное, например, на использование localStorage для сохранения данных вместо серверных служб.

Существует множество плагинов, упрощающих настройку поведения синхронизации Backbone.js. Например, подключаемый модуль Backbone.dualStorage позволяет использовать как внутренние службы, так и localStorage для сохранения данных. Когда ваше приложение отключается, подключаемый модуль использует localStorage, чтобы продолжать обслуживать запросы из кэшированных данных и отслеживать изменения, которые вы можете синхронизировать с сервером позже, когда будете в сети.

Хотя использование Backbone.js с серверной частью, разработанной для RESTful и совместимой с ним, проще в использовании, это не означает, что это все, с чем может работать Backbone.js. С некоторыми изменениями в механизме синхронизации Backbone.js по умолчанию вы можете адаптировать его к широкому спектру API внутренних служб и форматов кодирования.

Стоит отметить, что другие части Backbone.js также являются гибкими и в некоторых отношениях необязательными. Например, вам не нужно использовать механизм шаблонов по умолчанию, который поставляется с Underscore.js. Вам даже не нужно использовать компонент представления Backbone.js, и вы можете полностью заменить его чем-то другим, если хотите.

Ошибка № 7: Хранение данных в представлениях, а не в моделях

Одна ошибка, которую мы часто допускаем, когда начинаем изучать Backbone.js, заключается в хранении данных непосредственно в представлениях в виде атрибутов. Эти данные могут использоваться для отслеживания некоторого состояния или выбора пользователя. Это то, чего следует избегать.

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

Вы всегда можете создать несколько дополнительных моделей и коллекций без конечных точек. Это может помочь вам хранить данные, которые не обязательно должны сохраняться на серверной части или которые могут носить временный характер. Хранение их в моделях дает вам возможность прослушивать изменения. Соответствующее представление или даже несколько представлений могут наблюдать за этими моделями и при необходимости повторно отображать себя.

Представьте, что вы действительно храните переменные отслеживания состояния в представлениях и должны вызывать метод рендеринга каждый раз, когда вы их изменяете. Если пропустить хотя бы один вызов этого метода рендеринга, ваше приложение может остаться в сломанном состоянии с точки зрения того, что пользователь видит на экране. Более того, с небольшими представлениями вам может потребоваться синхронизировать эти переменные состояния на нескольких объектах представления, а затем также вызвать для них метод рендеринга.

Ошибка № 8: Использование jQuery «.on()» вместо делегированных событий

На мой взгляд, в Backbone.js есть один великолепный способ обработки событий DOM. Неиспользование влечет за собой кучу недостатков. Функция связывания событий jQuery «.on()» может показаться удобной, но в долгосрочной перспективе часто оказывается неудобной. Например, когда элементы отсоединяются от DOM, jQuery автоматически удаляет все обработчики событий, привязанные к элементам с помощью «.on()». Это означает, что любое событие DOM, к которому вы пытаетесь привязаться из представления, должно быть перепривязано, если вы отсоедините корневой элемент от DOM и снова присоедините его.

 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() { /* ... */ } }, // ... })

Когда элемент, соответствующий этому представлению, повторно присоединен к DOM, все, что вам нужно сделать, это вызвать «delegateEvents()» для представления, чтобы связать все эти события.

Обратите внимание, что важно понимать, как связаны эти события. Вместо привязки события к элементам, указанным селектором, Backbone.js фактически привязывает обработчик события к корневому элементу представления. Это прекрасно работает почти во всех случаях и даже лучше подходит для большинства наших нужд. Изменение или замена дочерних элементов в поддереве DOM представления не требует от Backbone.js повторной привязки каждого события к новым элементам. Существующие слушатели просто продолжают работать.

Однако это предотвращает прослушивание определенных событий. Одним из примеров является случай, когда вы можете захотеть прослушивать события прокрутки в «окне» или в дочернем прокручиваемом элементе. В случае дочерних элементов вы можете создать подвид для этого элемента и обрабатывать там события.

Заключение

Backbone.js, будучи очень компактным, но расширяемым фреймворком, является отличным выбором для веб-приложений, требующих большой внутренней гибкости. В отличие от таких фреймворков, как Angular.js и Ember.js, которые всегда подскажут вам, как делать то, что вы хотите, Backbone.js делает шаг назад, предоставляет вам мощный набор инструментов и позволяет вам решать, как использовать их. Я надеюсь, что это руководство по Backbone.js для начинающих поможет вам избежать некоторых распространенных ошибок разработки и создать с его помощью что-то потрясающее.