или как будущее декодирует прошлое.
В колледже я работал в комнате для прослушивания в подвале библиотеки колледжа в течение 3 лет. Это называлось «рабочая учеба». Это было частью моего пакета финансовой помощи. Это было несправедливо. Большинству моих одноклассников платили одинаковую почасовую оплату за работу в сфере общественного питания, которая напоминала работу в гораздо большей степени, чем то, что я сидел в комнате с кондиционером, просматривая компакт-диски, кассеты и виниловые пластинки, количество которых исчислялось десятками тысяч, иногда отправляя одну в наушники посетителю, который пришел выполнить домашнее задание на уроке композиции.
Среди стеков я несколько раз встречал Bitches Brew Майлза Дэвиса. Я знал, что этот альбом должен был быть важным, но обычно это заставляло меня чесать голову и выключать его в пользу какой-нибудь яванской музыки гамелана или, может быть, Master of Puppets Metallica.
Перенесемся на пару лет вперед. На сцену вышли Медески Мартин и Вуд.
Я слушал «Пятничный полдень во Вселенной» несколько десятков раз. И вуаля, когда я в следующий раз послушал Bitches Brew, что-то щелкнуло. Как будто я, наконец, "понял" после того, как испытал производную работу, которая представила дистиллированную сущность своего предшественника. Чтобы прояснить это, я полагаю, что MMW - это эволюционный результат BB. Ни BB, ни MMW.
Хорошо, это все, что касается музыкальной части этого поста. Извините. Перейдем к программистам.
Недавно у меня была возможность вернуться обратно в Backbone после года или около того, работая с React. Опыт был великолепен. Так много тонкостей библиотеки, которые я раньше полностью упустил, на этот раз просто щелкнул. На самом деле я обнаружил, что применяю уроки того, как делать что-то «способом React», к своему Backbone-коду.
Чтобы сделать связь между моими комментариями о музыке и кодом столь же тонкой, как летающий отбойный молоток (спасибо за выражение, Карл!), Я говорю, что React - это квинтэссенция предшествующего уровня техники, такого как как Backbone, и погружение в него помогло мне понять и лучше взаимодействовать с его предшественником, Backbone, точно так же, как прослушивание целой группы Medeski Martin и Wood помогло мне понять и оценить Bitches Brew.
Вот фрагмент кода, который демонстрирует мой стиль «первого восхождения» Backbone эм… доблесть ?:
к сведению: все мои старые образцы кода Backbone ссылаются на Goldstone Server, увлекательный проект, над которым меня наняли для работы с Solinea, который использовал d3 для создания многофункциональной интерфейсной панели для мониторинга и управления OpenStack. Я провел два года в качестве единственного разработчика JavaScript в проекте, полностью владея фронтенд-разработкой и, в конечном итоге, стал ведущим разработчиком.
var NewPasswordView = Backbone.View.extend({ initialize: function (options) { ... this.addHandlers(); }, addHandlers: function () { var self = this; $('.login-form').on('submit', function (e) { e.preventDefault(); var $password = $('#password'); var $confirm_password = $('#confirm_password'); if ($password.val() !== $confirm_password.val()) { goldstone.raiseWarning("Passwords don't match."); } else { self.submitRequest()... } }); } ... });
Почему это пахнет:
- Метод
addHandlers
работает для создания прослушивателя событий, но полностью упускает возможность использовать встроенныйevents
хеш, который Backbone предоставляет для этой цели. - Этот шаблон также требует использования очень злонамеренной ссылки
self
, чтобы сохранить контекст вызова при вызовеsubmitRequest
- Это создает прослушиватель событий с
.on
, который будет сохраняться даже после того, как это представление будет уничтожено, создавая утечки памяти, если не было принято меры для удаления активных слушателей с.off
. Оглядываясь назад на свой исходный код для этого представления, я вижу, что этого не было сделано8. Довольно тривиально для формы изменения пароля, которая вряд ли когда-либо будет использоваться, но плохой шаблон для входа, поскольку в часто загружаемых представлениях каждый экземпляр создает новый набор слушателей, которые будут продолжать добавлять к вашей проблеме утечки памяти.
Как это можно улучшить:
var NewPasswordView = Backbone.View.extend({ initialize: function (options) { ... // no longer needed --> this.addHandlers(); }, events: { 'submit .login-form': 'handleSubmit' }, handleSubmit: function(e) { e.preventDefault(); var $password = $('#password'); var $confirm_password = $('#confirm_password'); if ($password.val() !== $confirm_password.val()) { goldstone.raiseWarning("Passwords don't match."); } else { this.submitRequest... } } ... });
- теперь хэш событий регистрирует слушателя для события отправки, нацеленного на элемент
.login-form
. - в
handleSubmit
,submitRequest
можно вызывать без использованияself
для ссылки на правильный контекст выполнения.
Помимо ряда встроенных библиотечных методов, которые я игнорировал, более захватывающее развитие, которое можно наблюдать, и основная тема этой статьи - это переход от «монолитных представлений» к более мелким компонентам, которые появились после работы с React, и возвращение в Backbone.
После 18 месяцев работы над Goldstone, последние 6 месяцев с Solinea я потратил на разработку клиентского микросервиса для проекта SAAS с React / Redux. И с тех пор, последний год, я работал над личными проектами с React, и мне стало комфортно работать с библиотекой. Однако недавно меня наняли для выполнения клиентского проекта (который я добавил в свой профиль на github по этой ссылке), для которого идеальный процесс разработки должен был поддерживаться возвращением к Backbone (ах!) . Я не нахожу очень много упоминаний о людях, возвращающихся в Backbone после освоения React, но в этом случае большая часть разработки приложения заключалась в отображении коллекций данных в различных конфигурациях, чтобы помочь в создании годового календаря для Школьная система Нью-Йорка. Встроенные в Backbone функции сбора данных идеально подойдут для этой задачи, а функция View более чем адекватна.
Проверяя большинство моих Backbone Views в проекте Goldstone, они, как правило, разрастаются, охватывая функциональность для нескольких элементов на странице. Потратив некоторое время на работу с React и попрактиковавшись в Thinking In React, при возвращении к Backbone стало естественным начинать составлять функциональность из более мелких индивидуальных представлений, используя преимущества событий Backbone и сохранять состояние в моделях вместо использования такие вещи, как $ ('. foo'). val (). Другими словами, практика:
«Извлеките правду из DOM» - Джереми Ашкенас (создатель Backbone.js)
Вот пример (синтаксис ES6):
export const EventsView = Backbone.View.extend({ initialize() { this.collection = database; this.filterChooser = new FilterChooser(); this.individualEventBlock = new IndividualEventBlock({ model: this.filterChooser.model, collection: this.collection }); this.editModal = new EditModal({ collection: this.collection }); this.addModal = new AddModal({ collection: this.collection }); this.render(); this.listenTo(this.collection, 'updateEditModal', this.handleUpdateEventModal); }, onClose() { this.filterChooser.close(); this.individualEventBlock.close(); this.editModal.close(); this.addModal.close(); }, render() { this.$el.html(''); this.$el.append(addNewEventButton()); this.$el.append(this.filterChooser.el); this.$el.append(this.individualEventBlock.el); this.$el.prepend(this.editModal.el); this.$el.prepend(this.addModal.el); return this; }, events: { 'click .addEvent': 'handleAddEventModal' }, handleAddEventModal() { this.addModal.trigger('updateAddView'); }, handleUpdateEventModal(model) { this.editModal.trigger('updateEditView', model); } });
Отметить:
- Это представление верхнего уровня, которое отображается при переходе к
/events
. Его основная задача - создать экземпляры дополнительных компонентов, которые будут отображаться в представлении, и настроить пару слушателей. Слушатели устанавливаются с использованием хэшаevents
или с использованием синтаксисаlistenTo
, который позволяет очистить слушателей, когда представление закрывается маршрутизатором. - Для тех, кто знаком с работой с React, вы, вероятно, знакомы с концепцией хранения вашего состояния где-то в восходящем направлении, чтобы оно было доступно для подкомпонентов ниже по дереву компонентов. В функции
initialize
я использую то, что ссылки переменных на подкомпоненты находятся в одном месте, чтобы при необходимости разделять состояние между компонентами. Например: присвоение модели из filterChooser индивидуальному блоку событий. В IndividualEventBlock настроен прослушиватель, так что при изменении модели фильтра индивидуальный блок событий повторно визуализируется. - Я добавил
close
метод в Backbone.View через прототип. Он вызовет необходимые функции, чтобы отвязать слушателей. [см. примечание 1 внизу]. Если вы в прошлом занимались разработкой Backbone, вы можете узнать в этом паттерн, рекомендованный отличным (хотя и относительно старым) сообщением в блоге на тему предотвращения утечек памяти с помощью Backbone views.
Backbone.View.prototype.close = function(){ this.remove(); this.unbind(); if (this.onClose){ this.onClose(); } };
- В основной функции маршрутизации при замене представления вызывается метод
close
предыдущего представления. - Это отличается от «монолитного представления» тем, что каждое из этих подчиненных представлений включает гораздо меньший набор проблем, чем упаковка всего этого кода в одно представление.
Заключение:
Я не знаю, сколько людей осталось думать, что React - это просто еще одна модная вспышка в кастрюле, но если вы все еще используете библиотеку MV *, такую как Backbone, я рекомендую хотя бы попробовать React на некоторое время, пока шаблоны проектирования на основе компонентов щелкните. Я считаю, что даже если вы вернетесь к Backbone, это сделает вас лучшим разработчиком.
Эта статья является частью серии
[примечание 1]: когда я писал этот пост, готовясь описать относительные достоинства возможности отвязать слушателей в пределах представления, я понял, что на самом деле я еще даже не реализовал это в моем примере проекта. Фиксированный. Это первое опубликованное упоминание о «разработке, управляемой блогами»?