Постановка задачи
Совершенно случайно я превратился из питониста в JS-разработчика, и на мою хрупкую детскую психику обрушился непосильный груз вещей, которых в JS нет. Например, нет удобного форматирования строк. На питоне можно написать:
'hello, %(thing)s' % {'thing': 'world'}
Или вот так:
'hello, {thing}'.format(**{'thing': 'world'})
Ближайший аналог в JS — конкатенация (operator +
), которая очень плохо масштабируется с увеличением длины строки, да еще и выглядит безобразно до предела:
'<div class="input-append"><input type="text" name="username" '+
'id="signup_username" placeholder="'+placeholder+'"><input '+
'type="hidden" name="password" value="'+generated+'"><button '+
...
По возможности хотелось бы этого избежать.
Jeremy Ashkenas, когда разрабатывал CoffeeScript, также обратил на эту особенность JS внимание, и случайно диалект PHP:
"hello, #{document.cookie}"
Это тоже плохо, к тому же работает только для строковых литералов, загрузить шаблон из файла не получится.
Мне в этой штуке нравится похожий на Ruby синтаксис, но не нравится все остальное, особенно выполнение произвольного кода внутри строки. Таким образом постановка задачи:
– написать функцию
– которая подставляет переменные в строку
– загруженную из файла
– не PHP
Поиск решения
Обычно в таких случаях используют готовые библиотеки, более того, в NPM по слову template находится более двух тысяч пакетов.
В самом деле, mustache или lodash (underscore.js) работают превосходно, но… очень медленно: 10-20 мкс на одну подстановку. Не предел мечтаний ни в коем случае, особенно когда «продвинутый» функционал вроде циклов и фильтров совершенно не нужен.
А конкатенация, хоть и выглядит страшно, как звериный оскал коллективизма, работает все-таки в 10-30 раз быстрее. Таким образом, мы добавляем к постановке задачи:
– транслируется в конкатенацию
– и работает очень быстро
Вот теперь по этой спецификации можно изобретать велосипед. Because why not.
Что получилось
У меня получилась вот такая штука: Ruby-like simple string interpolation (GitHub)
В ней 9 строк кода, и она выполняет миллион триста тысяч подстановок в секунду (около 0,77 мкс на подстановку) на той же машине, где mustache делает 130 тысяч, а lodash/underscore 45 тысяч подстановок в секунду.
var hello = fmt('hello, #{thing}')
hello({thing: 'world'})
// -> hello, world
Вывод: за счет отказа от сложных функций шаблонизатора (циклы, условные выражения) было достигнуто ускорение в 10-30 раз по сравнению с популярными библиотеками, не прибегая к выполнению произвольного кода в шаблоне.
Rssi.js можно установить из npm очевидной командой npm install rssi
, поддерживается также Bower (bower install rssi
); на стороне клиента можно использовать AMD (RequireJS), а можно не использовать.
Спасибо за прочитывание этого не очень связного текста! Пишите патчи, господа хорошие, и до новых встреч.
Автор: printf