Если вы кого-нибудь спросите, на чем он делает клиентскую сторону своих приложений сегодня, этот человек наверняка ответит, что использует какой-нибудь хипстерский JS-фреймворк, вроде Angular, Ember, Knockout, Backbone или Polymer (смотрите сайт TodoMVC).
У большинства этих фреймворков есть «отличная» возможность, которая позволяет вам «легко» ссылаться на какую-либо информацию, используя дата-биндинги. Они выглядят примерно так:
<!-- Knockout -->
<p>Имя: <input data-bind="value: firstName" /></p>
<p>Фамилия: <input data-bind="value: lastName" /></p>
<h2>Привет, <span data-bind="text: fullName"> </span>!</h2>
<!-- Angular -->
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
<span>{{phone.name}}</span>
<p>{{phone.snippet}}</p>
</li>
</ul>
<!-- Ember -->
<div>
<label>Имя:</label>
{{input type="text" value=name placeholder="Введите ваше имя"}}
</div>
<div class="text">
<h1>Меня зовут {{name}} и я хочу выучить Ember!</h1>
</div>
Не смотря на то, что синтаксис немного варьируется, все они делают одно и то же. Они дают вам возможность встроить некоторые выражения в ваш HTML, которые «магически обрабатываются» фреймворком. Это означает — никаких ручных манипуляций DOM; вы можете писать красиво сформированный HTML внутри этих выражений и фреймворк сделает всю мирскую работу (вроде создания узлов, соединения обработчиков событий и обновления DOM при каких-либо изменениях моделей). Звучит это все конечно круто и не сложно заметить как все поддаются мейнстриму и разрабатывают этим путем.
Однако, получается, что все не так, как рекламируется; в подобном подходе есть существенные недостатки, которые остаются незамеченными, пока вы не пытаетесь сделать что-то сложное.
Там где я работаю, мы строим прототипы на многих из этих новых технологий чтобы определиться с ними для новых версий наших продуктов. Такое ощущение, что каждый разработчик, что использует один из этих модных фрейморков борется с ними и мы тратим кучу времени отлаживая проблемы или перекапывая StackOverflow в поисках решений элементарных (казалось бы) задач.
Некоторые из разочарований…
Никакой помощи от ваших инструментов
Из-за того, что эти биндинги не являются настоящими HTML-конструкциями, вы не получите никакой пользы от использования ваших инструментов с ними. Ни подсветки, ни авто-завершения кода, ни статического анализа или проверки типов. Скорее всего, в вашем HTML-редакторе эти выражения — просто строки.
Простые теги никогда не простые
Вы начнете с биндинга параметров вроде {{ name }}, но скоро окажется, что ваши выражения вырастают в сложный бардак. Вы поймете, что встроенная функциональность — не совсем то, что вам нужно и начнете гнуть свой фреймворк под дерьмо вроде этого, используя функцию JavaScript, которая возвращает функцию просто для применения фильтра с динамическим именем:
<tr
ng-show="banners"
ng-repeat="banner in banners.data"
>
<td ng-repeat="col in banner">
{{ col | dynamicFilter : banners.cols[$index].formatter }}
</td>
</tr>
<script>
myApp.filter('dynamicFilter', function ($filter) {
return function (value, filterName) {
if (Formatters[filterName])
return Formatters[filterName](value);
else
return value;
};
});
</script>
Ничего не работает с первого раза
После того, как ваши биндинги будут становиться сложнее, вы увидите, что они редко работают с первого раза. Вы закончите игрой в отладку дробовиком, твикая ваше выражение и перезагружая, надеясь увидеть правильную работу (это реально дерьмово, если у вас очень длинный цикл для возвращения в корректную точку тестирования, как например вручную делая логи вашего приложения).
Сообщения об ошибках редко существуют и часто бесполезны
Когда ваши биндинги работают неправильно, чаще всего вы не увидите ничего. Если вам повезет, вы увидите ошибку JavaScript. Если так, то она вам скажет что-то вроде «e is not a function» и даст вам весь стэк, который на 100 фреймов в глубине вашего фреймворка и ни одна его часть не ссылается на ваш HTML биндинг.
Отладка практически нереальна
Вы не можете поставить точку останова на {{тупой биндинг}}, потому что это не JavaScript (или всё-таки?). Чаще всего все закончится закидыванием его в “computed properties” или что-то аналогичное, но теперь ваш JavaScript заполнен дополнительными функциями на объектах, которые не имеют смысла вне фреймворк-специфичного модного вида. А все потому, что ваш фреймворк только наполовину парсит JavaScript выражения для биндингов.
В чем альтернатива?
Все очень просто. Программируйте на языке программирования. Не пытайтесь встроить его в ненормальные никогда-не-будущие-стандартом биндинги выдуманные ненадежными JavaScript фреймворками.
Вы наверняка не захотите полностью возвращаться к манипулированию DOM вручную, но ведь есть варианты вроде React (без JSX, поскольку JSX сосет по некоторым причинам описанным выше), который избегает манипуляциями DIM (вместо проповедования идеи описания «текущего положения») и сохраняет весь код как код. Таким образом, все ваши существующие инструменты, минимизаторы и т. д. будут работать отлично. Хотите извлечь функцию чтобы использовать ее еще раз? Без проблем! Хотите переименовать/рефакторить? Без проблем. Хотите использовать TypeScript и иметь поддержку проверки типов в ваших выражениях? Без проблем (TypeScript+React вместе работают лучше).
На работе, один из наших разработчиков строит прототип на React, и я также строю один на Dart (вдохновленный React, генерирующий код элементов, пока я надеюсь, что Dart TagTree превратиться в удобную для использования библиотеку). Ни один из этих прототипов не подвержен тем же проблемам, что эти ужасные {{ глупые биндинги }} в HTML.
HMTL — декларативный язык разметки. Оставьте это так и прекратите пытаться всунуть туда нестандартные биндинги.
Автор: