Самый быстрый JavaScript-фреймворк

Нашел еще один JavaScript-фреймворк (спасибо Виктору за наводку), который на несколько порядков быстрее всех остальных. Прошу любить и жаловать vanilla.js! Если верить создателям, то получение всех элементов по имени тега отрабатывает быстрее jQuery в 425 раз. Я думаю, одного этого достаточно, чтобы глянуть на фреймворк.

AngularJS

Вы, наверное, слышали об этом JavaScript-фреймворке. Модный тренд, если позволите так выразиться. Superheroic JavaScript MVW1 Framework, как утвержают сами разработчики. Не удержался и посмотрел на него, тем более что выдалась возможность сделать это в рабочее время и за счет заказчика. Мы выбираем основу для будущего проекта, вот и решили глянуть современные js фреймворки, и мне достался AngularJS. Поделюсь своими впечатлениями.

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

<table class="table table-striped table-hover" ng-controller="TestController">
    <thead>
        <tr>
            <th>Action</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="action in actions">
            <td>{{action.action}}</td>
        </tr>
    </tbody>
</table>

Дальше мы подключаем JavaScript:

function TestController($scope) {
    $scope.actions = [
        {action: 'Action1'},
        {action: 'Action2'}
    ];
}

Ну и всё. У нас готова страница с таблицей, в которой 2 строки: «Action1» и «Action2». Но это еще не все. Если мы потом добавим в поле actions еще чего-нибудь, то оно тоже автоматически отобразится на странице.

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

В общем, впечатление от фреймворка очень положительное, надо будет попробовать написать что-нибудь более-менее серьезное.

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


  1. Model-View-Whatever

JavaScript и приведение типов

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

[]+[] 
> ""
[]+{}
> "[object Object]"
{}+[]
> 0
{}+{}
> NaN

Почему так? Это кажется бредом, пока не разберешься с системой типов в JavaScript. Ладно-ладно, это кажется бредом в любом случае, но тем не менее попробуем хоть чуть разобраться.

Самое главное, что нужно знать — операция + работает только с примитивными типами. Т.е. что бы вы ни написали, выражение будет приведено к этим типам. Даже больше: если хотя бы один операнд — строка, то и результат будет строкой. Поэтому, чтобы понять причину происходящего выше, нужно узнать, как объекты и массивы приводятся к примитивным типам.

У каждого объекта и массива (ведь массив тоже объект) есть 2 метода: valueOf и toString. И именно они будут использоваться для преобразования типов. Сначала интерпретатор вызывает valueOf, и если он вернул не примитивное значение, то вызывается toString. Теперь нужно выяснить, что же возвращают эти методы у {} и [].

console.log({}.valueOf());  // Возвращает себя
console.log([].valueOf());  // [] (тоже себя)
console.log([].toString()); // ""
console.log({}.toString()); // "[object Object]"

Засада. Каким образом {}+[] дает 0, ведь по логике должно быть "[object Object]"? Ковыряние в спецификации пока ни к чему не привело. Если кто знает правильный ответ, не томите, поделитесь наблюдениями.

Ну и совсем напоследок видео, из-за которого я начал разбираться в этой теме. Посмотрите, не пожалеете.

UPD: Исправлен верхний листинг.

UPD2: Разгадка.

Source map

Итак, у вас очень много JavaScript-кода. А значит, вы его сжимаете перед тем, как отдавать клиенту. Наверняка даже используете YUI Compressor или Google Closure Compiler. А может, вы пишете свой client-side код на чем-нибудь модном: на Dart или CoffeeScript? В любом случае вы наверняка сталкивались с проблемой отладки и поиска ошибки в браузере. Попробуй угадать, почему в 3-й строчке на 100501 позиции значение переменной aAz вдруг стало undefined. А ведь до компиляции скрипта всё работало как надо! Я в таких случаях начинаю добавлять в код много инструкций console.log, чтобы хоть как-то проследить процесс выполнения кода.

Ну что ж, у меня для вас хорошие новости. В Google знают о ваших проблемах и даже придумали решение — source map. Идея проста: компилятор должен создавать специальный файл с информацией о соответствии скомпилированного кода не скомпилированному, а браузер должен брать информацию из этого файла и показывать красоту вместо абракадабры.

Расскажу, какие шаги мне пришлось проделать, чтобы source map заработал в этом блоге. Сразу предупреждаю, что на рабочем сайте вы его не найдете, он существует только на моей локальной машине, но вы можете попробовать собрать всё из исходников сами.

  1. Включаем генерацию source map в Google Closure Compiler. Для этого используется опция компилятора --create_source_map=./script.js.map.
  2. Файл получили. Но в нем скорее всего прописаны неправильные пути к исходным файлам, особенно если ваш корень сервера не совпадает с корнем проекта. Придется их поправить, например, вот такой unix-командой: sed -i 's/"static\//"\//g' static/js/script.js.map.
  3. Чтобы браузер знал о наличии файла с картой, нужно добавить комментарий в конец скомпилированного js-фала: echo "//@ sourceMappingURL=script.js.map" >> static/js/script.testing.js.
  4. Ну и последний этап, нужно включить поддержку source map в Google Chrome. Для этого открываем Developer Tools (Ctrl+Shift+I), нажимаем на кнопку настроек в правом нижнем углу и ставим галочку напротив «Enable source maps».

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

А теперь ложка дегтя. Она одна, но зато большая: поддержка. Как это обычно бывает с новыми технологиями, не все успевают или не все хотят реализовывать всякие экспериментальные поделки. Поэтому мы будем довольствоваться только одним браузером — Google Chrome. Ребята из Mozilla тоже трудятся над поддержкой source maps, но работающего результата у них пока нет. А вот запрос «ie source maps» ожидаемо выдает 0 релевантных результатов.

Та же беда с Source Maps и в языках и компиляторах. Я нашел поддержку только в Google Closure Compiler и Dart, а так же зачатки в CoffeeScript. Если знаете еще кого-нибудь, кто поддерживает — добро пожаловать в комментарии.

Скажу, что спецификация так же предусматривает source map и для CSS файлов, но я пока не тестировал эту возможность.

Ну и напоследок пара ссылок: на спецификацию и на обзор.

Просто так

Что-то давно я ничего не постил в блог. Не хорошо получается. Поэтому расскажу вкратце, чем же таким я занимался всё это время. Во-первых, я переписываю javascript часть блога с jQuery на Google Closure. Почему? Потому что таким образом значительно уменьшится размер и количество js-файлов (в идеале, остаться должен только один). Ну и плюс к этому лучше проникаюсь концепциями, скрытыми в архитектуре этого фреймворка.

Во-вторых, поставил себе TeamCity и пытаюсь разобраться, как применить CI к разработке на Haskell. В конце концов, хотелось бы получить автоматическое обновление сайта после обновления ветки production на GitHub.

А еще недавно случился день программиста. По этому поводу я посетил новый офис Prontosoft и полюбовался, как у них теперь хорошо:

Prontosoft

Prontosoft

← СтаршеМоложе →