Нашел еще один JavaScript-фреймворк (спасибо Виктору за наводку), который на несколько порядков быстрее всех остальных. Прошу любить и жаловать vanilla.js! Если верить создателям, то получение всех элементов по имени тега отрабатывает быстрее jQuery в 425 раз. Я думаю, одного этого достаточно, чтобы глянуть на фреймворк.
Вы, наверное, слышали об этом 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
. Чтобы это понять, официального сайта было недостаточно, и пришлось провести пару-тройку часов в обнимку с дебаггером и гуглом.
В общем, впечатление от фреймворка очень положительное, надо будет попробовать написать что-нибудь более-менее серьезное.
Еще примеры можете оценить на главной странице фреймворка, они там гораздо лучше, чем я вам привел.
Model-View-Whatever
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: Разгадка.
Итак, у вас очень много JavaScript-кода. А значит, вы его сжимаете перед тем, как отдавать клиенту. Наверняка даже используете YUI Compressor или Google Closure Compiler. А может, вы пишете свой client-side код на чем-нибудь модном: на Dart или CoffeeScript? В любом случае вы наверняка сталкивались с проблемой отладки и поиска ошибки в браузере. Попробуй угадать, почему в 3-й строчке на 100501 позиции значение переменной aAz
вдруг стало undefined
. А ведь до компиляции скрипта всё работало как надо! Я в таких случаях начинаю добавлять в код много инструкций console.log
, чтобы хоть как-то проследить процесс выполнения кода.
Ну что ж, у меня для вас хорошие новости. В Google знают о ваших проблемах и даже придумали решение — source map. Идея проста: компилятор должен создавать специальный файл с информацией о соответствии скомпилированного кода не скомпилированному, а браузер должен брать информацию из этого файла и показывать красоту вместо абракадабры.
Расскажу, какие шаги мне пришлось проделать, чтобы source map заработал в этом блоге. Сразу предупреждаю, что на рабочем сайте вы его не найдете, он существует только на моей локальной машине, но вы можете попробовать собрать всё из исходников сами.
- Включаем генерацию source map в Google Closure Compiler. Для этого используется опция компилятора
--create_source_map=./script.js.map
. - Файл получили. Но в нем скорее всего прописаны неправильные пути к исходным файлам, особенно если ваш корень сервера не совпадает с корнем проекта. Придется их поправить, например, вот такой unix-командой:
sed -i 's/"static\//"\//g' static/js/script.js.map
. - Чтобы браузер знал о наличии файла с картой, нужно добавить комментарий в конец скомпилированного js-фала:
echo "//@ sourceMappingURL=script.js.map" >> static/js/script.testing.js
. - Ну и последний этап, нужно включить поддержку 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 и полюбовался, как у них теперь хорошо: