понедельник, 12 августа 2013 г.

10 причин почему ваш проект должен использовать Dojo Toolkit

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

1. Модульность и AMD загрузчик

Клиентский JavaScript код, как и любой код, склонен расти в размерах. Модульность является тем ключем, который делает наш код легко поддерживаемым и производительным. Дни использования библиотек использующих единовременную, без асинхронной докачки, загрузку, остались в прошлом. Dojo Toolkit является ярким примером фреймворка использующего модули. Он использует dojo.require для того, чтобы динамически подтягивать только те ресурсы, которые нужны странице в данный момент.

Изначально метод загрузки ресурсов был синхронным, хотя существовал и кросс-доменный вариант с возможностью асинхронной загрузки. Сейчас Dojo использует асинхронный загрузчик, написанный Рэвилдом Гиллом (Rawld Gill), который мастерски загружает все ресурсы асинхронно и намного быстрее чем раньше. Чтобы загрузить несколько JavaScript ресурсов вы можете написать, что-то типа этого:

// Функция require сообщает загрузчику, что необходимы модули из первого массива
// Если модуль из списка уже был загружен, то он будет взят из кэша
require(
        // Массив модулей требующих загрузки
        ["dojo/on", "dojo/touch", "dijit/form/Button", "dojo/domReady!"],
        // Функция, которая будет вызвана после загрузки всех модулей,
        // с объектами модулей переданными ей в качестве аргументов.
        // Модули должны быть перечислены в том же порядке, что и в массиве требований
        function(on, touch, Button) {
                // Здесь выполняем нужные нам действия с загруженными модулями.
});

Модуль объявляется очень просто:

// Используем 'define' вместо 'require' потому, что мы хотим объявить модуль
define(
        // Объявляем модули, которые потребуются нашему модулю
        ["dojo/aspect", "dojo/_base/declare", "dijit/layout/BorderContainer"],
        // Функция обратного вызова, которая должна вернуть объект
        function(aspect, declare, BorderContainer) {
                // Указываем имя модуля и модули от которых он унаследован
                // После чего возвращаем модуль (объект или функцию)
                return declare("mynamespace.layout.CustomBorderContainer", [BorderContainer], {
                        // Описываем здесь свойства и методы нашего модуля.
        });
});

Этот простой способ объявления модуля, используемый почти всеми AMD загрузчиками, невероятно прост и структурирован.

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

Многофункциональный Dojo загрузчик также предоставляет возможность использования плагинов. Таких, как определения готовности DOM (dojo/domReady!) и функции определения (hasJS). Кроме того, загрузчик достаточно умен, чтобы загружать разные модули в зависимости от внешних условий:

// Этот код используется в dojo/Deferred модуле
define([
        "./has",
        "./_base/lang",
        "./errors/CancelError",
        "./promise/Promise",
        "./has!config-deferredInstrumentation?./promise/instrumentation"
], function(has, lang, CancelError, Promise, instrumentation){
        // ...
});

Dojo это не просто максимальная модульность, но и готовый загрузчик модулей для ваших задач.

2. Классы и рассширяемость с dojo/declare

В то время, как JavaScript не предоставляет настоящей системы классов, Dojo Toolkit предоставляет классоподобный паттерн наследования основанный на использовании dojo/declare. Declare реализован во фреймворке так, что позволяет разработчикам:

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

Система классов Dojo использует прототипное наследование. Использование dojo/declare невероятно просто:

// Конечно, вы должны использовать **define** для создания модуля
define([
        // Подключим модуль предоставляющий **dojo/declare**
        "dojo/declare",
        // Также подключим зависимости класса, который мы собираемся использовать
        "dijit/form/Button",
        "dojo/on",
        "mynamespace/_MyButtonMixin" // Имена примесей следует начинать с "_"
], function(declare, Button, on, _MyButtonMixin) {
        // Возвращаем результат метода declare(), который и является нашим классом
        return declare(
                // Первый аргумент это имя виджета. Вы должны использовать объектный синтаксис
                "mynamespace.CustomButton",
                // Вторым аргументом является родительский класс.
                // Для множественного наследования следует использовать массив.
                [ Button, _MyButtonMixin ],
                // Наконец, объект, который содержит новые свойства и методы, или
                // другие значения для унаследованных свойств и методов
                {
                        myCustomProperty: true,
                        value: "Hello!",
                        myCustomMethod: function() {
                                // делаем что-то здесь!
                        },
                        methodThatOverridesParent: function(val) {
                                this.myCustomMethod(val);
                                // Вызываем "this.inherited(arguments)" для выполнения
                                // родительского метода с теми же параметрами
                        return this.inherited(arguments);
                }
        });
});

Привиденный пример не решает никакой практической задачи, но иллюстрирует повторное использование кода через цепочку наследования и примесь, а также показывает, как класс может вызвать метод родительского класса.

Еще одним преимуществом использования системы классов Dojo является то, что все свойства и методы являются настраевыемыми. Всё может быть легко изменено и расширено в течении всего процесса создания класса.

3. Аспекты и “функция к функции событий”

Аспекты являются одним из самых мощных и важных новых веяний в веб-разработке... и Dojo Toolkit предоставляет их в течении многих лет. Вместо запуска функции после обычного пользовательского события: “click”, “mouseover”, “keyup” - аспекты позволяют вызвать функцию В до или после того, как функция А выполнится. По сути, вы можете подключать функции к функциям - и это круто!

Запуск одной функции после другой выглядит так:

// after(объект, имя метода, вызывемая функция, ее аргументы);
aspect.after(myObject, "someMethod", function(arg1, arg2) {
        // Код, который будет выполнен после завершения метода myObject.doSomething
}, true);

Запуск функции до выполнения другой тоже абсолютно прост:

aspect.before(myObject, "someMethod", function(arg1, arg2) {
        // Код, который будет выполнен до вызова метода myObject.someMethod
});

Аспекты черезвычайно полезны при создании пользовательского интерфейса с использованием Dijit. Прослушивание событий на одном виджете или классе может вызвать изменения в других виджетах. Это позволяет разработчикам создавать один большой виджет из многих маленьких.

var self = this;
aspect.after(this.submitButton, "onClick", function() {
        // Нажатие кнопки отправки выполняет дополнительный функционал
        self.showAjaxSpinner();
});

4. Deferred и унифицированный AJAX транспорт

Deferreds являются объектно-ориентированными представлениями асинхронных операций, что позволяет легко передавать состояния операция от одного места к другому. Одним из самых последних и важных дополнений JQuery было Deferreds. Так совпало, что мантра команды Dojo является “Dojo это сделал”. Dojo Toolkit содежит реализацию Deferreds уже в течении нескольких лет, используя их для простых и сложных операций AJAX, анимации и многого другого.

Наряду с тем, будучи одним из первых, кто реализовал объекты Deferred, Dojo ввел несколько методов обработки ввода-ввывода стандартного XMLHTTPRequest, в том числе window.name обертку, модуль dojo/io/iframe для асинхронной загрузки файлов и многое другое. Так когда в Dojo используются Deferred объекты? Всякий раз, когда происходит асинхронное действие. Deferreds возвращаются из XHR запросов, dojo/io запросов, анимации и многого другого.

// Отправляем XHR запрос, получая в ответ **Deferred**
var def = xhr.get({
        url: "/getSomePage"
});
// Навесим много функций обратного вызова
def.then(function(result) {
        result.prop = 'Something more';
        return result;
}).then(function(resultObjWithProp) {
        // ....
}).then(function() {
        // ....
});

А как выглядит использование API модуля dojo/io/iframe?

require(["dojo/io/iframe"], function(ioIframe){
        // Посылаем запрос
        ioIframe.send({
                form:           "myform",
                url:            "handler.php",
                handleAs:       "json"
        }).then(function(data){
                // Обработчик успешного результата
        }, function(err){
                // Обработчик ошибки
        }). then(function() {
                // Больше функций обратного вызова!
        })
});

Красота использование Deferred в Dojo заключается в том, что внезависимости от метода, вы знаете, что всегда будете получать в ответ объект Deferred, ускоряя развитие и объединение API. Начиная с версии 1.8 в Dojo доступен модуль dojo/request, добавляющий новые методы консолидации AJAX. Вот пример, как может быть использован dojo/request:

require(["dojo/request"], function(request){
        request("request.html").then(function(response){
                // выполняем какие-то действия с результатом запроса
        }, function(err){
                // обработчик ошибок
        }, function(evt){
                // обработка смены статуса запроса
        });
});

Унифицированный API делает разработку быстрее, а код компактнее.

5. Dijit UI Framework

Без сомнения, самым большим преимуществом Dojo Toolkit перед другими JavaScript фреймворками является его Dijit UI фреймворк. Это беспрецедентный набор лэйаутов, форм и других инструментов:

  • полная локализация из коробки;
  • расширенный макет виджетов для облегчения 100% высоты элементов, создания пользовательских разделителей, изменения лэйаута и т.д.;
  • виджеты формы с улучшенным удобством и встроенной поддержкой валидации;
  • много тем оформления, новейшая называется “Claro”;
  • поддержка LESS в пользовательских темах;
  • модульный код, что позволяет полную пользовательскую настройку любых виджетов, а также расширение их возможностей.

Dijit позволяет объявлять виджеты декларативно и программно. Декларативное объявление выглядит так:

<div data-dojo-type="dijit.form.Button" data-dojo-props="label:'Click Me!'"></div>

Традиционный способ объявления виджетов выглядит следующим образом:

require(["dijit/form/Button"], function(Button) {
        // Создаем кнопку программно
        var button = new Button({
                label: 'Click Me!'
        }, "myNodeId");
});

Существует несколько десятков виджетов предоставляемых пакетом Dijit и еще несколько десятков предоставляемых в пакете Dojox. Фреймворк Dojo UI это не просто несколько полезных виджетов пользовательского элемента, как, например, JQuery UI, это полноценный протестированный фреймворк для создания пользовательских интерфейсов.

6. Dojo Mobile

Как и почти на все проблемы Интернета, Dojo имеет решение для мобильной веб-разработки - модули пространства имен dojox/mobile. Мобильное решение от Dojo предоставляет:

  • определение устройств;
  • темы для iOS, Android, Blackberry, а также базовую;
  • мобильные виджеты для формы;
  • панели и макеты для виджетов;
  • поддержка десктопа для облегчения разработки и отладки.

Мобильные виджеты могут быть созданы декларативно или программно, аналогично Dijit виджетам. Мобильные экраны поддерживают ленивый рендеринг и могут легко обмениватся данными. HTML каркас для dojox/mobile очень прост:

<!DOCTYPE html>
<html>
<head>
        <meta name="viewport" 
content=
"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"/> <meta name="apple-mobile-web-app-capable" content="yes" /> <title>Название вашего приложения</title> <!-- место для пользовательский стилей --> <!-- место для dojo/javascript --> </head> <body> <!-- приложение будет здесь --> </body> </html>

С помощью модуля dojox/mobile/deviceTheme мы можем определять устройство пользователя и применять соответствующие стили.

После задания темы подключим модули необходимые нашему приложению:

require([
        "dojox/mobile/ScrollableView",
        "dojox/mobile/Heading",
        "dojox/mobile/RoundRectList",
        "dojox/mobile/TabBar",
        "dojox/parser"
]);

После того как все подключили опишем декларативно наши виджеты и экраны:

<!-- пример взят с Dojo's TweetView:
        http://dojotoolkit.org/documentation/tutorials/1.7/mobile/tweetview/app/ -->

<!-- экраны твитов -->
<div id="tweets" data-dojo-type="dojox.mobile.ScrollableView" data-dojo-props="selected: true">
   <h1 data-dojo-type="dojox.mobile.Heading">
          <!-- кнопки обновления -->
          <div
                data-dojo-type="dojox.mobile.ToolBarButton"
                data-dojo-props="icon: 'images/refresh.png'"
                class="mblDomButton tweetviewRefresh"
                style="float:right;">
          </div>
          Tweets
   </h1>
   <ul data-dojo-type="dojox.mobile.RoundRectList">
          <li data-dojo-type="dojox.mobile.ListItem">
                 Tweet
          </li>
   </ul>
</div>

<!-- экраны упоминаний -->
<div id="mentions" data-dojo-type="dojox.mobile.ScrollableView">
        <h1 data-dojo-type="dojox.mobile.Heading">
                <!-- кнопки обновления -->
                <div
                        data-dojo-type="dojox.mobile.ToolBarButton"
                        data-dojo-props="icon: 'images/refresh.png'"
                        class="mblDomButton tweetviewRefresh"
                        style="float:right;">
                </div>
                Упоминания
        </h1>
        <ul data-dojo-type="dojox.mobile.RoundRectList">
                <li data-dojo-type="dojox.mobile.ListItem">
                        Mention tweet
                </li>
</ul>
</div>

<!-- настройки экранов -->
<div id="settings" data-dojo-type="dojox.mobile.ScrollableView">
        <h1 data-dojo-type="dojox.mobile.Heading">Settings</h1>
        <h2 data-dojo-type="dojox.mobile.RoundRectCategory">Show</h2>
        <ul data-dojo-type="dojox.mobile.RoundRectList">
                <li data-dojo-type="dojox.mobile.ListItem">
                        Здесь настройки элемента.
                </li>
        </ul>
</div>

Принципы использования виджетов dojox/mobile абсолютно идентичны принципам использования виджетов Dijit. Это позволяет быстро освоится тем, кто уже имеет опыт работы с Dijit, а новичкам обеспечивает легкое освоение предлагаемых виджетов.

7. GFX и диаграммы

CSS анимация является отличным инструментом визуализации, как анимированные изображения, но уступает в гибкости и мощи векторной графике. Самым популярным инструментом для создания векторной графики на стороне клиента всегда был Raphael JS, но GFX библиотека Dojo, несомненно, мощнее. GFX может быть настроен для отображения векторной графики в SVG, VML, Silverlight, Canvas и WebGL. GFX обеспечивает удобную обертку для создания всех форм векторной графики (эллипс, линия и т.д.), что ускоряет создание графики. Dojo GFX поддерживает:

  • наклон, поворот и изменение размера графики;
  • анимация заполнения, строкер и другие графические свойства;
  • линейный и круговой градиент;
  • события мыши;
  • группирование форм для упрощения управления и анимации.

Создание простого набора фигур может выглядеть так:

require(["dojox/gfx", "dojo/domReady"], function(gfx) {
        gfx.renderer = "canvas";
        // Создаем GFX поверхность
        // Аргументы:  узел, ширина, высота
        surface = gfx.createSurface("surfaceElement", 400, 400);
        // Создаем круг и задаем ему цвет текстом
        curface.createCircle({ cx: 50, cy: 50, rx: 50, r: 25 }).setFill("blue");
        // Создаем круг и задаем ему цвет в hex формате
        surface.createCircle({ cx: 300, cy: 300, rx: 50, r: 25 }).setFill("#f00");
        // Создаем круг с линейным градиентом
        surface.createRect({x: 180, y: 40, width: 200, height: 100 }).
        setFill({ type:"linear",
                x1: 0,
                y1: 0,   //x: 0=>0, градиент постоянен по горизонтали
                x2: 0,   //y: 0=>420, и меняется по вертикали
                y2: 420,
                colors: [
                        { offset: 0,   color: "#003b80" },
                        { offset: 0.5, color: "#0072e5" },
                        { offset: 1,   color: "#4ea1fc" }
                ]
        });
        // Создаем круг с радиальным градиентом
        surface.createEllipse({
                cx: 120,
                cy: 260,
                rx: 100,
                ry: 100
        }).setFill({
                type: "radial",
                cx: 150,
                cy: 200,
                colors: [
                        { offset: 0,   color: "#4ea1fc" },
                        { offset: 0.5, color: "#0072e5" },
                        { offset: 1,   color: "#003b80" }
                ]
        });
});

Dojo содержит библиотеку dojox/charting использующую API Dojo GFX. Визуализация информации с помощью графиков пользуется популярностью и не зря - сложно получить полную картину просто просматривая числа. Библиотека dojox/charting позволяет:

  • множественные графики;
  • анимированные графики;
  • плагины, в том числе MoveSlice (анимирует части круговой диаграммы), подсказка, масштабирование и подсветка;
  • самообновляющиеся диаграммы (используют Dojo хранилища данных).

Базовую круговую диаграмму можно создать с помощью следующего кода:

<script>
        // x и y координаты используются для облегчения понимания места расположения
        // Данные представляют посетителей сайта за недельный период
        chartData = [
                { x: 1, y: 19021 },
                { x: 1, y: 12837 },
                { x: 1, y: 12378 },
                { x: 1, y: 21882 },
                { x: 1, y: 17654 },
                { x: 1, y: 15833 },
                { x: 1, y: 16122 }
        ];
        require([
                "dojo/parser",
                "dojox/charting/widget/Chart",
                "dojox/charting/themes/Claro",
                "dojox/charting/plot2d/Pie"
        ]);
</script>
<!-- создание места для диаграммы -->
<div
        data-dojo-type="dojox.charting.widget.Chart"
        data-dojo-props="theme:dojox.charting.themes.Claro" id="viewsChart" 
style=
"width: 550px; height: 550px;"> <!-- добавим круговую диаграмму --> <div class="plot" name="default" type="Pie" radius="200"
fontColor=
"#000" labelOffset="-20"></div> <!-- укажем источник данных --> <div class="series" name="Last Week's Visits" array="chartData"></div> </div>

Хотя приведенный выше код создает только простую круговую диаграмму, dojox/charting способен на много, много большее.

8. Dgrid от команды SitePen

SitePen, компанию специализирующуюся на консультациях по Dojo, создал сооснователь Dojo Дилан Шиман (Dylan Schiemann). Ее сотрудники пытались найти замену чрезмерно раздутому и неуклюжиму dojo/Grid и в итоге создали dgrid. Основные особенности получившегося пакета:

  • многочисленные темы и легкое создание своих тем;
  • полная совместимость с мобильными браузерами;
  • сортировка строк;
  • возможность отложенной загрузка данных;
  • поддержка древовидной структуры;
  • возможность редактирования ячеек таблицы используя виджеты dijit;
  • различные расширения: изменение размеров столбцов, drag’n’drop, постраничная навигация и многое другое.

SitePen проделал выдающуюся работу по документированию каждого компонента dgrid, поэтому начать создание собственных многофункциональных таблиц будет невероятно просто.

9. Тестировочный фреймворк DOH

Тестирование на клиентской стороне очень важно. Едва ли не более важно, чем на стороне сервера. С учетом количества браузеров и разнообразия функционала различных версий браузеров интерактивное тестирование становится обязательным. Фреймворк DOH созданный для тестирования Dojo доступен вместе с интрументарием Dojo. Написание тестов невероятно легко, а сами тесты могут быть представлены в нескольких форматах:

// Зададим имя тестового модуля для того, чтобы сделать загрузчик немного счастливее
dojo.provide("my.test.module");

// Зарегистрируем тест
doh.register("MyTests", [
        // Тесты могут быть простыми функциями
        function assertTrueTest(){
                doh.assertTrue(true);
                doh.assertTrue(1);
                doh.assertTrue(!false);
        },
        // ... или объектами со свойствами: name, setUp, tearDown, and runTest
        {
                name: "thingerTest",
                setUp: function(){
                        this.thingerToTest = new Thinger();
                        this.thingerToTest.doStuffToInit();
                },
                runTest: function(){
                        doh.assertEqual("blah", this.thingerToTest.blahProp);
                        doh.assertFalse(this.thingerToTest.falseProp);
                // ...
                },
                tearDown: function(){
                }
        },
        // ...
]);

Приведенный выше пример теста очень простой. Но как насчет более сложной ситуации, т.е. асинхронных действий? Наиболее очевидные примеры асинхронных действий это AJAX, анимация и другие отложенные действия. DOH предоставляет невероятно простой способ для тестирования асинхронных действий с использованием объектов doh.Deffered:

{
        name: "Testing deferred interaction",
        timeout: 5000,
        runTest: function() {
                var deferred = new doh.Deferred();
                myWidget.doAjaxAction().then(deferred.getTestCallback(function(){
                        doh.assertTrue(true);
                });
                return deferred;
        }
}

В приведенном выше примере функция “getTestCallback” будет запущена после окончания работы метода “doAjaxAction” и вернет результат теста.

Последующие тесты не будут запущены, пока не разрешит doh.Deferred, таким образом не нужно засекать время и нет проблемы пересекающихся тестов. DOH предоставляет возможности для тестов значительно превосходящие другие другие фреймворки. DOH также предоставляет Java-робота, который полностью эмулирует действия мыши и клавиатуры, для более точного и реалистичного тестирования. Если вы слышите крик Гомер Симпсона “Woohoo!”, то все тесты пройдены. Но если вы слышите страшное “DOH!”, то значит вам нужно пересмотреть свой код с целью исправления ошибок.

10. Процесс сборки Dojo

Когда веб-приложение готово к выпуску, невероятно важно ради оптимизированной загрузки и кэширования создать минифицированные и правильно разбитые на слои JavaScript файлы. Это снижает нагрузку на сайт.

Система сборки Dojo анализирует объявленные классы и автоматически определяет зависимости при сборке. Чтобы использовать систему сборки Dojo вы создаете то, что называется профилем сборки. Построенный профиль может содержать многочисленные слои и быть довольно сложным. На привиденном ниже примере представлен простейший профиль сборки:

var profile = {
        releaseDir:     "/path/to/releaseDir",
        basePath:               "..",
        action:                 "release",
        cssOptimize:    "comments",
        mini:                   true,
        optimize:               "closure",
        layerOptimize:  "closure",
        stripConsole:   "all",
        selectorEngine: "acme",
        layers: {
                "dojo/dojo": {
                        include: [ "dojo/dojo", "app/main" ],
                        customBase: true,
                        boot: true
                }
        },
        resourceTags: {
                amd: function (filename, mid) {
                        return /\.js$/.test(filename);
                }
        }
};

Профиль сборки Dojo позволяет разработчику настраивать:

  • минификатор (ShrinkSafe от Dojo или Closure от Google)
  • уровень минификации;
  • директория сборки;
  • механизм селекторов;
  • и многое другое.

Построенный профиль запускается с помощью командной строки (недавно переписан на Node.js) и может дополнятся или корректироватся с помощью различных аргументов. Небольшой пример запуска профиля сборки:

./build.sh --profile /path/to/app/app.profile.js --require /path/to/app/boot.js

Процесс сборки Dojo обеспечивает невероятное количество контроля над генерацией файлов сборки и завершает процесс оптимизации веб-приложения. С минифицированными и разбитыми на слои JavaScript и CSS файлами ваше веб-приложение готово к показу!

11. Bonus! Сундук сокровищ Dojo. Больше Dojox

Две очень важные библиотеки Dojox уже упоминались выше: Dojox Mobile и GFX, но это только два из множества скрытых сокровищ представленных в Dojo. Эти сокровища включаются в себя:

  • дополнительные макеты и виджеты;
  • передовые и локализованные процедуры валидации форм;
  • WebSocket и long-polling обертки;
  • виджеты представлений, такие как лайтбокс, слайдшоу, галерея и прочее;
  • расширенные IO помощники;
  • расширенная библиотека Drag’n’Drop;
  • расширения модуля NodeList.

И это тоже только часть из множетства драгоценных камней Dojo.

Dojo Toolkit представляет собой всеобъемлющий инструментарий JavaScript:

  • основные JavaScript и вспомогательные утилиты;
  • расширенный JavaScript и AJAX утилиты;
  • асинхронные сценарии загрузки;
  • полный UI фреймворк;
  • полный тестировочный фреймворк;
  • средства сборки;
  • и многое другое!

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