Статьи

Я отдал свое одеяло безопасности JQuery и жил, чтобы рассказать сказку

 


Ребекка опубликовала это в своем блоге после публикации в журнале JSmag за 2009 год.

Недавно у меня была возможность спроектировать интерфейс нового веб-приложения с нуля, и после нескольких лет использования jQuery я решил попробовать Dojo . По разным причинам — не в последнюю очередь из-за подхода Dojo к организации кода и управлению зависимостями — я подумал, что это будет хороший проект, чтобы получить некоторый реальный опыт работы с Dojo. Далее следует обзор Dojo с точки зрения заядлого пользователя jQuery. Я использую jQuery в течение многих лет. Его простота соблазнительна; через некоторое время он вроде пишет сам. И, возможно, это была моя проблема: я был готов попробовать что-то новое. Много месяцев назад я написал в Twitter, что мне было интересно узнать больше о Dojo. Рей Банго, jQuery evangelist, написал ответ и связал меня с Питом Хиггинсом , руководителем проекта Dojo. Пит месяцами лоббировал меня, чтобы попробовать свой «единый инструментарий». Я баловался. Я читаю документы. Пит показал мне пример кода, чтобы показать, чего мне не хватало, и даже поехал в Северную Каролину, чтобы возглавить лагерь в Додзё. В августе я решил, что пора перестать баловаться и погрузиться. Я только что закончил писать некоторый, по сути, безбиблиотечный JavaScript для веб-приложения для iPhone, и эта задача позволила мне быть более уверенным в своих знаниях JavaScript. Когда мобильный сайт был закрыт, клиент был готов создать настольную версию, а я отвечал за интерфейс. Пришло время выбрать библиотеку; на этот раз я выбрал додзё.

Выбор Додзё

Решение попробовать новую библиотеку в клиентском проекте было непростым — я знал, что могу написать основную функциональность сайта, используя jQuery, намного быстрее, чем написать в Dojo, просто потому, что знал свой путь к jQuery. намного лучше. Использование Dojo означало бы, что я буду искать много вещей, от простых вещей, таких как, как работать с выборами DOM, до более сложных задач, таких как, как структурировать мой код для целей повторного использования и абстракции. По мере того, как моя работа над проектом прогрессировала, а сроки приближались, у меня появилось много мыслей. Несколько вещей убедили меня придерживаться Додзё, когда дела шли плохо

 

  • Шаблоны организации кода: Dojo предоставляет довольно четкие рекомендации по структурированию как ваших функций, так и базы кода. Я много думал об организации кода JQuery. Я написал статью на эту тему для JSMag и выступил с докладом на эту тему на конференции jQuery. Мне очень хотелось попробовать библиотеку, которая явно отвечает на вопрос организации.
  • Наследование классов: с самого начала я знал, что собираюсь использовать множество шаблонов взаимодействия снова и снова. Я хотел иметь возможность писать эти шаблоны таким образом, чтобы я мог использовать их в разных функциях, оставаясь при этом сухим. Наследование классов, предоставляемое dojo.declare (), было элегантным и простым в использовании решением проблемы.
  • Управление зависимостями: возможность легко управлять зависимостями была для меня огромным преимуществом; это способствует повторному использованию и абстракции в значительной степени. Управление зависимостями Dojo также проложило бы путь к простому созданию готовых к работе файлов, которые бы объединяли все необходимые функциональные возможности для страниц определенного типа, уменьшая количество требуемых HTTP-запросов.
  • Описание методов обслуживания: Это конкретное приложение широко использовало XHR (AJAX). Подход к описанию метода обслуживания в Dojo позволил бы мне управлять URL-адресами и параметрами для этих запросов в одном месте, сохраняя части, которые могут меняться, отдельно от основного кода. В конце концов, теоретически серверный код может автоматически сгенерировать этот SMD-файл. Подробнее об этом чуть позже.
  • Шаблонирование: Все ответы XHR были в формате JSON, который мне нужно было превратить в HTML. В jQuery есть плагины-шаблоны для решения этой проблемы, так что на самом деле это не было отличительным фактором, но тем не менее это облегчит мою жизнь. Я мог бы поддерживать шаблоны для преобразования JSON в HTML отдельно от моего JavaScript и даже программно выбирать шаблон в зависимости от ситуации.
  • Смысл этого: при связывании функции с событием элемента в jQuery это внутри функции ссылается на элемент, который вызвал событие. Возможно, это желательно для простого кода, но когда вы начинаете организовывать свой код в объекты с помощью методов и хотите, чтобы это ссылалось на объект, а не на элемент, это может стать болезненным. Метод dojo.hitch () позволяет вам полностью изменить значение этого значения для любой данной функции, и он прозрачно свернут в другие методы, такие как dojo.connect () для привязки событий.
  • Документация и поддержка: Dojo имеет репутацию плохой документации и в некоторой степени это заслужено. Их документация намного сложнее в использовании, чем в jQuery, потому что, на первый взгляд, она гораздо более разрозненная и существенно более API-ориентированная, чем основанная на задачах. Однако, как только я понял, где искать нужные мне документы , найти ответы на мои вопросы было довольно безболезненно. Я также опирался на некоторых опытных разработчиков Dojo для руководства и поддержки, и заглянул на постоянно полезный IRC-канал #dojo на Freenode, если я застрял.

Начиная

Первым шагом была сборка моей новой игрушки. Я решил использовать библиотеку через CDN Google, чтобы как можно быстрее приступить к работе. После этого пришло время выяснить, как я могу организовать свои файлы. Dojo активно поддерживает пространства имен для компонентов, что означает, что вы можете поместить файлы приложения в один или несколько каталогов и связать свои пространства имен с этими каталогами. Я создал файл контроллера высокого уровня в каталоге root / js; он будет отвечать за выяснение того, какая функциональность требуется для данной страницы (решение, которое я в конечном итоге пересмотрю). Затем я создал каталог внутри каталога root / js, куда я поместил бы все отдельные файлы для различных компонентов.

Наконец, я включил строку в свой файл контроллера, чтобы сообщить Dojo, где найти пространство имен, которое я буду использовать: dojo.registerModulePath (‘myNamespace’, ‘../js/myNamespace’); Выяснение всех этих частей, возможно, было самой трудной частью перехода на Dojo — это была намного более сложная настройка, чем я привык к jQuery, и хотя все это задокументировано, потребовалось немного усилий, чтобы найти детали и получить пути, настроенные правильно. Время, которое потребовалось, чтобы все работало должным образом, было временем, которое я потратил на размышления о том, принял ли я правильное решение. Когда все заработало, пришло время написать какой-то реальный код и попытаться ответить на этот вопрос.

Получить некоторые элементы, сделать что-то с ними

Эти слова подводят итог парадигме jQuery. В jQuery вы запрашиваете DOM, используя селектор CSS, и результатом этого запроса является объект jQuery, с которым вы затем можете работать, используя цепочки методов. В jQuery довольно редко работает напрямую с элементом DOM. Хотя Dojo поддерживает эту парадигму с помощью метода dojo.query () и возвращаемого им NodeList, в Dojo принято работать непосредственно с элементом DOM, а не с NodeList. Сначала я хотел придерживаться того, что я знал из jQuery, и использовать dojo.query (), чтобы получить все, с чем я хотел работать. Однако, когда я начал копаться, я обнаружил, что на самом деле может быть столь же элегантно (и дешевле) работать непосредственно с элементами DOM, даже если они не сопровождаются магией объекта jQuery. Синтаксис для этого был немного другим — например, dojo.addClass (myDomElement,’foo’) вместо $ (myDomElement) .addClass (‘foo’) — но чем больше кода я написал, тем чаще и легче я использовал вместо этого синтаксис dojo.addClass. Использование такого подхода было особенно ценным, когда речь шла о методах, которые что-то возвращали. Например, метод dojo.connect () (используется для подключения событий к элементам, аналогично $ (). Bind ()) возвращает объект подключения, который можно сохранить и отключить позже, не зная, к какому элементу было присоединено событие. к. Одним словом, это круто. Это также пример того, как Dojo требует, чтобы вы немного по-другому думали о том, как вы пишете свой JavaScript.Использование такого подхода было особенно ценным, когда речь шла о методах, которые что-то возвращали. Например, метод dojo.connect () (используется для подключения событий к элементам, аналогично $ (). Bind ()) возвращает объект подключения, который можно сохранить и отключить позже, не зная, к какому элементу было присоединено событие. к. Одним словом, это круто. Это также пример того, как Dojo требует, чтобы вы немного по-другому думали о том, как вы пишете свой JavaScript.Использование такого подхода было особенно ценным, когда речь шла о методах, которые что-то возвращали. Например, метод dojo.connect () (используется для подключения событий к элементам, аналогично $ (). Bind ()) возвращает объект подключения, который можно сохранить и отключить позже, не зная, к какому элементу было присоединено событие. к. Одним словом, это круто. Это также пример того, как Dojo требует, чтобы вы немного по-другому думали о том, как вы пишете свой JavaScript.Это также пример того, как Dojo требует, чтобы вы немного по-другому думали о том, как вы пишете свой JavaScript.Это также пример того, как Dojo требует, чтобы вы немного по-другому думали о том, как вы пишете свой JavaScript.

Возвращение результата для победы

В связи с этим мне пришлось привыкнуть к тому, что многие методы Dojo возвращали объекты, с которыми я мог поговорить позже. Например, dojo.animateProperty () создал объект анимации, который позже можно было бы воспроизвести play () ‘d. Все методы XHR — и асинхронные методы в целом — возвращали «отложенный» объект, к которому я мог позже добавить обратные вызовы успеха и неудачи. jQuery возвращает нативный объект XHR из его метода $ .ajax (), так что вы также можете технически добавлять туда обратные вызовы. Что мне понравилось в отложенном подходе Dojo, так это то, что он предоставляет общий простой интерфейс для взаимодействия со всеми асинхронными операциями и даже позволяет вам определять свои собственные. Освоение того, как извлечь выгоду из этих вещей, потребовало некоторых усилий, исходя из более процедурного, связанного мира jQuery, где практически все возвращает объект jQuery. Однако вскореЯ настраивал анимации задолго до того, как был готов к их воспроизведению, и добавлял обратные вызовы в XHR после их запуска.

SMD: унифицированный способ общения с сервером

Одна вещь, которую я действительно хотел попробовать в Dojo, это использовать описания методов обслуживания или SMD. Файл SMD в основном содержит информацию обо всех услугах, предоставляемых ресурсом. В моем случае ресурсом было серверное приложение, с которым я связывался для запроса данных JSON. Создав файл SMD, а затем создав новую службу на основе этого файла, я мог бы создать единое место для управления всеми путями и параметрами, которые я использовал бы для получения того, что мне нужно от сервера. Когда я запрашивал у сервера что-то, созданный мною сервис возвращал отложенный объект, к которому я мог прикрепить обратные вызовы. В фоновом режиме Dojo просто запускал XHR, но моим отдельным классам не нужно было беспокоиться о деталях — мне просто нужно было беспокоиться о названии метода и параметрах, которые ему необходимы,и Служба, которую я определил и создал, позаботится обо всем остальном. Для моей первоначальной работы я просто создал файл SMD вручную, но в итоге легко увидеть, как SMD может быть сгенерировано самим приложением на стороне сервера. Вот пример SMD (обычно SMD имеет гораздо больше сервисов, очевидно):

{
  transport        : 'GET',
  envelope         : 'PATH',
  target           : '/json',

  services         : {
    callouts : {
      parameters : [ { name : 'callouts', type : 'string' } ],
      returns : 'object'
    }
  }
}

А вот сокращенный код, который использует SMD:

cache : {},

services : new dojox.rpc.Service(dojo.moduleUrl('smd', 'json.smd')),

postCreate : function() {
  // ...
},

_lookup : function() {
  var val = this.domNode.value;

  if (this.cache[val]) {
    this._handleResult(this.cache[val]);
  } else {
    var c = this.services.json.callouts({ 'callouts' : val });

    c.addCallback(dojo.hitch(this, function(resp) {
      this.cache[val] = resp;
    }));

    c.addCallback(dojo.hitch(this, '_handleResult'));
  }
},

_handleResult : function(resp) {
  // ...
}
 

Управление зависимостями и построение

Я люблю jQuery, но мне это очень не хватает. Он предлагает мало рекомендаций о том, как структурировать вашу кодовую базу, как обеспечить загрузку всего, что вам нужно, или как встроить ваш код в готовые файлы. Додзё действительно сияет здесь, но опять же, нужно немного привыкнуть. Базовый dojo.js включает в себя массу базовых функций, но мне пришлось быстро научиться делать дополнительные функции dojo.require () по мере необходимости. В jQuery вы бы сделали это, просто добавив другой тег script в ваш HTML; dojo.require () в основном делает это для вас программно, но проверяет, что необходимый код еще не был включен первым. Это означает, что каждому из ваших компонентов может потребоваться именно то, что ему нужно, и совершенно безопасно требовать одного и того же более одного раза.Обратная сторона этого заключается в том, что, если вы забыли потребовать что-то, что вам нужно, или если вы требуете, используя неправильное имя, не всегда ясно, где именно вы совершили ошибку. Каждый файл, который будет dojo.require (), начинается с оператора dojo.provide (), сообщающего системе управления зависимостями, что он действительно нашел нужный файл. После этого файл может перейти к dojo.require () со своими собственными зависимостями, которые Dojo загружает перед продолжением работы с остальным кодом файла. Метод dojo.provide () также устанавливает цепочку объектов по пути; например, если вы dojo.provide (‘abcd’), вы можете безопасно выполнить abcde = {…}. Когда приходит время собирать ваши отдельные файлы в готовые комбинированные минимизированные файлы, система сборки Dojo может анализировать операторы dojo.require () и автоматически включать соответствующие файлы;с jQuery это гораздо более ручной процесс, который может быть трудно поддерживать. Создание сборки не было таким простым, как я надеялся, и я много чего наткнулся на этом пути. Потребовалось немало усилий, чтобы все пути были правильными и выяснить, как создать повторяемый процесс сборки, который мы могли бы свернуть в нашем полном процессе выпуска. Однако, отдача была большой: я мог сохранять свои файлы в порядке, как я хотел, но обслуживать только один файл. Система сборки выяснила шаги между ними.и выяснить, как получить повторяемый процесс сборки, который мы могли бы свернуть в нашем полном процессе выпуска. Однако, отдача была большой: я мог сохранять свои файлы в порядке, как я хотел, но обслуживать только один файл. Система сборки выяснила шаги между ними.и выяснить, как получить повторяемый процесс сборки, который мы могли бы свернуть в нашем полном процессе выпуска. Однако, отдача была большой: я мог сохранять свои файлы в порядке, как я хотел, но обслуживать только один файл. Система сборки выяснила шаги между ними.

Организация, Наследование и Абстракция

Как я уже упоминал выше, организация кода была большой проблемой для меня с jQuery. Я разработал несколько шаблонов, которые я использую для поддержания нормального кода, но многие другие разработчики jQuery этого не делают, что может сделать работу с кодом других людей довольно болезненной. Конечно, с помощью Dojo можно написать процедурный, неорганизованный код, dojo.declare () предоставляет ясный способ избежать этого. Ранее я говорил о создании пространства имен для моего кода и связанного с ним каталога. Когда пришло время начать писать, я создал отдельные файлы в этом каталоге для каждого компонента на странице. Внутри каждого файла я указывал, какой компонент файл предоставлял с помощью dojo.provide (), загружал любые зависимости с помощью dojo.require (), а затем создал класс в пространстве имен с помощью dojo.declare (). Метод dojo.declare () принимает три аргумента:имя класса, который вы хотите создать («myNamespace.Thinger»), другие классы, которые вы хотите «смешать» с вашим новым классом (если есть — этот аргумент может быть нулевым, отдельным классом или массивом классов) и, наконец, объект, который определяет методы и свойства класса. Результатом является класс, который может быть создан с использованием нового myNamespace.Thinger (); созданный объект инкапсулирует все поведения и состояния, связанные с конкретным Thinger, и вы можете иметь столько экземпляров Thinger, сколько захотите. Микширование в вещи огромно, потому что оно позволяет вам иметь класс, который включает методы, определенные в другом классе. Например, я создал класс myNamespace.Toggler, который будет показывать либо первый элемент в списке, либо все элементы в списке; щелчок по первому элементу списка переключал бы между поведениями. Когда-то myNamespace.Был создан класс Toggler, другие классы могли наследовать его поведение, просто передав ссылку на класс myNamespace.Toggler в качестве второго аргумента dojo.declare (). Я смог инкапсулировать поведение Toggler повторно и сохранить код для классов, унаследовавших поведение Toggler, красивым и чистым.

Управление событиями

Ранее я упоминал, что Dojo имеет несколько иной подход к привязке событий, чем jQuery. Я должен также сказать, что вы можете привязать события ко всем NodeLists (результат dojo.query ()), если хотите, используя .connect () (или вспомогательные методы, такие как .onclick () и т. Д.). Однако, если вы хотите ссылку на соединение для последующего использования, dojo.connect () — ваш друг. Я создал компонент с помощью dojo.declare (), который отвечал за управление взаимодействием пользователей с элементом пользовательского интерфейса со звездным рейтингом. Я использовал dojo.connect (), чтобы подключить некоторые элементы mouseover / mouseout к элементу, и сохранил возвращенные соединения как свойства компонента. Когда щелкнул элемент, я зарегистрировал рейтинг и хотел, чтобы поведение при наведении курсора мыши / мышке исчезло; их устранение было просто вопросом dojo.disconnect () — сохранения сохраненных соединений.

Опубликовать и подписаться

Поскольку весь трафик XHR происходит на странице, я хотел, чтобы он отключался, если пользователь какое-то время был неактивен, но я не хотел писать код для обработки этого внутри каждого компонента, использующего XHR. Инструменты паба / саб додзё предлагали идеальный ответ. Я создал новый компонент, единственной целью которого было следить за бездействием; когда он обнаруживал неактивность, он делал dojo.publish (‘/ user / inactive’). Тогда другие компоненты — те, которые я уже написал, и те, которые я напишу в будущем — могут подписаться на / user / неактивную тему и реагировать соответствующим образом. Pub / sub — отличный способ разрешить такую ​​абстрактную связь между компонентами. Компоненту, который публикует «тему», не важно, кто слушает; компоненту, который подписывается на тему, не важно, какой компонент отправил ее.Это еще один пример того, как Dojo заставляет вас немного по-другому думать о том, как вы разрабатываете свои приложения — знание о pub / sub может помочь вам написать гораздо более слабосвязанный код.

Что я пропустил из jQuery

С методами, связанными с делегированием событий jQuery .live () и .is () было трудно жить. Есть разумный способ имитировать .is (), но нет замены «из коробки» .live () — в итоге вы сами пишете делегирование события. Dojo имеет dojo.behavior (), который автоматически связывает обработчики событий с элементами, которые соответствуют заданному селектору, когда они добавляются на страницу; однако обработчики событий привязаны к отдельным элементам, и нет способа предоставить контекст для селектора, который вы передаете в dojo.behavior (). Это может быть мой разговор с noob-ness, или, может быть, я просто привык к сообщениям об ошибках, которые я видел, когда делал что-то не так с jQuery, но я часто чувствовал, что сообщения об ошибках от Dojo были слишком загадочными. Хуже того, иногда я делал что-то не так, и это казалось бы молчаливым.Я провел намного больше времени в Firebug, отслеживая ошибки моих путей. Вообще, то, что я действительно упустил из jQuery, это аспект «все работает» библиотеки. Я ожидаю, что со временем я почувствую то же самое в отношении Додзё, но в то же время, безусловно, возникают проблемы с ростом. Мне приходилось постоянно напоминать себе, что способ решения проблемы в Додзё может быть не таким, каким я бы решил в jQuery. Я не раз переписывал множество кода, когда обнаруживал методологию или подход Dojo, о которых раньше не знал.Мне приходилось постоянно напоминать себе, что способ решения проблемы в Додзё может быть не таким, каким я бы решил в jQuery. Я не раз переписывал множество кода, когда обнаруживал методологию или подход Dojo, о которых раньше не знал.Мне приходилось постоянно напоминать себе, что способ решения проблемы в Додзё может быть не таким, каким я бы решил в jQuery. Я не раз переписывал множество кода, когда обнаруживал методологию или подход Dojo, о которых раньше не знал.

Вывод

Чтобы Рей не беспокоился о том, что он никогда не должен был представлять меня Питу, не бойтесь: я не собираюсь бросать jQuery в ближайшее время. Во всяком случае, я рад видеть, как развивается библиотека и сообщество, и начинает отвечать на некоторые вопросы организации и управления зависимостями, которые я упомянул выше. Как библиотека, jQuery определенно имеет свое место; у него практически нет барьеров для входа, и это помогло вступить в эру, в которой очень просто создавать многофункциональные интерактивные веб-сайты. Решение использовать Dojo вместо этого было чем-то вроде азартной игры. Мне пришлось убедить руководителя проекта, что это было хорошее решение, которое было сложным, учитывая популярность библиотеки jQuery. Он задал много острых вопросов о поддерживаемости кода, если я собираюсь покинуть проект, и эти вопросы были вполне заслуженными. Если что, хотя,Я думаю, что выбор Dojo фактически повысил удобство сопровождения кода, предоставив четкие шаблоны для организации, абстракции и управления зависимостями. Потребовалось ли время, чтобы набрать скорость с Додзё? Точно. Сможет ли разработчик jQuery с улицы перейти прямо к коду, который я написал? Возможно нет. В конце концов, однако, это всего лишь JavaScript, и любой опытный разработчик JavaScript должен быть в состоянии обойти это. Они почти наверняка обнаружат, что через час или два код, который я написал, будет легче следовать, чем часть кода jQuery, с которым я столкнулся, который не использует хорошие принципы организации. А пока я надеюсь поработать над проектом какое-то время,и я ожидаю, что трудность, с которой я столкнулся, чтобы ускориться в Dojo, принесет большие дивиденды по мере роста и развития приложения, над которым я работаю.