В последнее время мы эпизодически возвращаемся к теме JavaScript. Нас особенно заинтересовала очередная книга из серии «You Don't Know JS», посвященная стандарту ES6 (Кайл Симпсон):
Кстати, может быть кто-то уже присматривался к новой книге Адама Бодуха "JavaScript at Scale" и хотел бы увидеть ее на русском языке?
Об этом в опросе. А под катом — критическая (январская) статья мистера Коди Линдли, помогающая задуматься о том, насколько мир JavaScript готов к переменам.
В мире веб-разработки на JavaScript для больших предприятий создаются такие решения и применяются такие инструменты, которые должны хотя бы в минимальном объеме функционировать в условиях ECMAScript 3 (стандарт ES3). Вы вправе удивиться – а как такое может быть? В конце концов, ECMAScript 5 был готов еще в июне 2011 года и поддерживается всеми современными браузерами, в том числе, IE 9 (если не считать строгого режима).
В этой статье мы поговорим о том, почему многие, если не все JavaScript-разработчики с больших предприятий по-прежнему должны учитывать ES3, а также обсудим ряд стратегий для тех, кто хочет сегодня пользоваться возможностями ES5/ES6. Наконец, я расскажу, почему сам так не делаю.
IE8 никуда не делся. Привыкните к этому.
Поддержка IE 8, 7 и даже 6 по-прежнему может оставаться актуальным требованием на предприятии. Хотите вы того или нет, согласны ли с этим — так есть. Иными словами, использование возможностей JavaScript ES5 или ES6 в боевом коде — во многих корпоративных окружениях по-прежнему остается делом будущего.
Код, создаваемый корпоративными разработчиками, и инструменты, с которыми они работают, в принципе должны поддерживать ES3-окружения. Например, большинство виджетов в Kendo UI (не считая мобильных) тестируются и поддерживаются в IE7+. Даже бегло изучив практически любое JavaScript-решение, написанное для корпоративных разработчиков, убеждаешься, что большинство таких решений создаются с учетом стандартов ES3.
Это не должно удивлять никого, кто набил руку на корпоративной разработке. Однако порой трудно смириться с тем, что многие новейшие инструменты JavaScript (например, Angular 1.3) тестируются и разрабатываются без всякой оглядки на идеальную работу в чистых ES3-средах, да и могут вообще там не прижиться. Как минимум, там они могут спровоцировать серьезные неприятности, потребовать обходных маневров и полифиллов.
В настоящее время корпоративные инструменты зачастую воспринимаются и превозносятся как исключительно надежные, первоклассные, проверенные временем, заточенные на решение только самых сложных задач, какие могут вставать перед программистом. Но реальность такова, что большая часть enterprise-кода на JavaScript и соответствующих инструментов написаны и стандартизированы под спецификацию, которая была окончательно доработана 16 лет назад.
Бесспорно, стандарт ES3 проверен временем, но вот насчет его высокой надежности и пригодности для большого предприятия, думаю, многие нынешние JavaScript-разработчики могли бы поспорить. В конце концов, возможности из новых спецификаций ES5 и ES6 по определению создавались именно для исправления огрехов ES3 и для того, чтобы современный JavaScript позволял решать столь сложные задачи, какие сегодня перед ним ставятся. Причем можно не сомневаться, что одних лишь возможностей, реализованных 16 лет назад, недостаточно для современной JavaScript-разработки.
Каков план действий для разработчика?
Представляю, насколько мрачно все это звучит для среднестатистического JavaScript-разработчика из большой корпорации. Я, как специалист по JavaScript, сам хотел бы, чтобы все мои коллеги уже могли приступать к работе с новыми возможностями JavaScript, не дожидаясь их окончательной доработки и реализации. Браузеры и корпорации, будьте вы прокляты!
Но между желаемым и действительным большая разница. Думаю, именно поэтому и делаются полифиллы для имитации новых возможностей, люди компилируют JavaScript для старых браузеров или вообще забрасывают клиентский код и осваивают Node. Не смейтесь, так бывает. Клиент и браузер в самом деле могут настолько достать разработчика, что он очертя голову кинется на поиски более качественной среды выполнения для JavaScript.
Серьезно, самое разумное для корпоративного разработчика, использующего инструментарий ES3 и пишущего код, работающий в среде ES3 — просто делать свое дело. Думаю, вам никто не мешает мечтать, что когда-нибудь можно будет забыть о поддержке старых браузеров (ES3) и создавать только современный нативный код под ES5 или ES6. Разумеется, enterprise-разработчикам придется ждать отмирания старых браузеров — прямо скажем, на большом предприятии это произойдет не скоро.
ПОЧЕМУ Я НЕ ПОЛЬЗУЮСЬ ПОЛИФИЛЛАМИ ИЛИ КОМПИЛЯЦИЕЙ
Лично я никогда не пытался использовать масштабные полифиллы и не прибегал к компиляции, чтобы сделать рабочий ES3-код из ES5 или ES6. Да, я эпизодически прибегал к полифиллам, но мне никогда не удавалось справиться с теми сложностями и издержками, которые сопряжены со всесторонним применением полифиллов или процедурой компиляции (то есть, создать рабочий ES3-код из исходного кода ES5 или ES6). Подводные камни, дополнительные полифиллы, ограничения в использовании и неполноценные возможности — вот что удерживало меня от этого. Например, попробуйте просто почитать обо всех деталях, связанных с использованием возможностей ES6 при применении нового компилятора 6to5.
Это не означает, что я не смаковал, не программировал и не использовал новые возможности JavaScript, когда у меня появлялся такой шанс. Тоже так поступайте. Дело в том, что когда от меня требуется поддержка среды ES3, я избираю путь наименьшего сопротивления, заключающийся в следующем: обходиться такими инструментами и писать такой код, который максимально близок к «металлу» ES3. Наконец, тот лишь факт, что инструмент требует ES5+, еще не означает, что он сможет работать в условиях ограничений, присущих другому стороннему решению, связанному с полифиллами или компиляцией – конечно, если это решение не будет заранее тестироваться и поставляться с необходимыми полифиллами, что по понятным причинам (размер файла, синхронизация, дублирование и т.д.) обычно не делается.
Итак, я почти не прибегал ни к полифиллам, ни к компиляции. Я считаю, что создание приложения на JavaScript — само по себе безумно сложное предприятие. Малейшие усложнения большого корпоративного проекта, издержки или бюрократия (тем более — сторонняя бюрократия) оправданны лишь в том случае, если дают принципиальный выигрыш в разработке. В моей практике такого выигрыша ни разу не удалось бы достичь, добавив новые возможности JavaScript в базу кода, рассчитанную на ES3 — настолько это сложно.
Но со мной согласятся не все. Разумеется, у каждого свой допустимый предел дополнительной сложности или оправданного риска. Поэтому в рамках этой статьи я полагаю, что вы, в отличие от меня, решились использовать в базе кода ES3 такие возможности, которые появились в более поздних спецификациях (обратите внимание: я говорю о полифиллах для стороннего кода).
Стратегии использования новых возможностей ES6+ JavaScript на предприятии
В оставшейся части этой статьи мы исследуем 3 стратегии использования новых возможностей ES6+ JavaScript на предприятии.
СТРАТЕГИЯ 1. ПРИМЕНЕНИЕ ВСТАВНЫХ ПОЛИФИЛЛОВ
До отказа полизаполнить среду ES3 возможностями из стандартов ES5 и ES6 (и даже из ES7) очень просто — достаточно включить файл shim.js из проекта core.js в HTML-документ.
shim.js включается в HTML-документ в качестве первого JavaScript-файла для запуска/синтаксического разбора, и весь остальной код JavaScript, следующий за ним, можно задействовать возможности полифиллов как нативные (ниже приведены примеры кода из core.js).
console.log(Array.from(new Set([1, 2, 3, 2, 1]))); // => [1, 2, 3]
console.log('*'.repeat(10)); // => '**********'
Promise.resolve(32).then(console.log); // => 32
setImmediate(console.log, 42); // => 42
Учтите, что в core.js не только предоставляется полный набор ECMAScript-совместимых полифиллов, но и следующие нестандартные возможности JavaScript, доступные при использовании core.js вместо shim.js.
- Mozilla JavaScript: Array generics
- setTimeout / setInterval
- setImmediate
- console
- Object
- Dict
- Partial application
- Date formatting
- Array
- Number
- Escaping characters
СТРАТЕГИЯ 2. ИСПОЛЬЗОВАНИЕ ПОЛИФИЛЛОВ ПО ПРИНЦИПУ OPT-IN
Хотим мы того или нет, рассмотренные выше вставные полифиллы добавляют в ES-среду новые возможности во время исполнения. Любой ценой. Если вас это не устраивает, то есть другой вариант. В проекте core.js также предлагаются явно подключаемые (opt-in) полизаполнения, реализующие новые возможности, но эти возможности можно использовать и выборочно, активируя каждую из них по отдельности. Подобная практика применяется в библиотеках наподобие lodash, предлагающих одно глобальное значение (например _), на которое завязаны все возможности.
Чтобы явно подключать возможности ES5 и ES6 в вашем коде, можно включить файл library.js из core.js. Затем можно применять новые возможности ECMAScript по мере необходимости, написав код, обращающийся к тем возможностям метода, которые завязаны на глобальном значении ‘core’. Подобная ситуация реализована в следующем образце кода (пример взят из core.js).
var log = core.console.log;
log(core.Array.from(new core.Set([1, 2, 3, 2, 1]))); // => [1, 2, 3]
log(core.String.repeat('*', 10)); // => '**********'
core.Promise.resolve(32).then(log); // => 32
core.setImmediate(log, 42); // => 42
СТРАТЕГИЯ 3. ПРЕДВАРИТЕЛЬНАЯ КОМПИЛЯЦИЯ ES6+ В ES5 С ПОСЛЕДУЮЩИМ ПРИМЕНЕНИЕМ ПОЛИФИЛЛОВ ДЛЯ ES3
Стандартные возможности ES5 и ES6 нельзя напрямую компилировать в код ES3 (например, использовать старые возможности для написания более новых, эквивалентных им). В противном случае вы серьезно ограничите те возможности. которые можно было бы транслировать. Было бы реально использовать этап предварительной компиляции, на котором код ES6 компилируется в ES5, а затем задействовать вставной полифилл shim.js, чтобы преодолеть последний перегон до ES3.
Для этого можно воспользоваться новым транспилятором 6to5 и создать предварительную задачу сборки, в которой используется gulp, преобразующий ES6 в немодифицированный (ванильный) ES5. Затем, согласно документации 6to5, чтобы получить полноценную среду времени исполнения для ES6, также потребуется подготовить эту среду при помощи полифиллов regenerate runtime, shim.js и ES6 module loader (обратите внимание: я использую client/shim.js из core.js, где обеспечивается поддержка ES3).
HTML-файл, содержащий код, скомпилированный при помощи 6to5, может выглядеть примерно так:
<!DOCTYPE html>
<html>
<body>
<script src="runtime.js"></script>
<script src="client/shim.js"></script>
<script src="es6-module-loader.js"></script>
<script>
System.parser = '6to5'; // задать es6-module-loader.js для работы с 6to5
// далее идет код, скомпилированный с 6to5
</script>
</body>
</html>
Просто не забывайте, что если делаете это в коммерческом коде, то я настоятельно рекомендовал исследовать абсолютно все возможные нюансы.
Что насчет стороннего кода?
Теоретически, если вы полизаполнили или полизаполнили + предварительно скомпилировали код, чтобы обеспечить использование новых возможностей JavaScript в среде ES3, то сможете смело задействовать сторонние инструменты, работающие только в средах ES5+, верно? Нет!
Практически единственный вариант, позволяющий безопасно использовать в среде ES3 сторонний инструмент – это прямая поддержка вашего конкретного полифилла/компилятора на уровне стороннего кода. В противном случае посылка из первого абзаца этого раздела остается весьма стремной и временной. Помните, все это запиливание новых возможностей в старые окружения связано с теми или иными подводными камнями, сложными уловками и личными мнениями. Не следует рассчитывать, что сторонний разработчик имел дело с подобными деталями, если только вы лично не убедились, что эти разработчики в точности ориентируются на вашу среду. Если вы не вполне меня понимаете, просто учтите, что сторонние разработчики вряд ли будут тестировать полифиллы и скомпилированный вывод. Как правило, если для синтаксического разбора стороннего кода требуется среда ES5+, то имеется в виду реальная среда ES5+.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (15)
rock
21.08.2015 14:05+6Старенькая статья. Какбэ
6to5
давно вbabel
переименован, да и ссылочки наcore-js
поправить не мешало бы, например, форматирование даты давно в отдельную библиотеку вынесено, а абстрактные ссылки (по ссылке ES7) удалены (вернее, разделены) как из предложений для ES7, так и изbabel
иcore-js
.trikadin
30.08.2015 02:55И дело не только в устаревании названий/ссылок — бабель сильно вырос как инструмент, и вполне спокойно можно компилить код даже для IE8 (если нужно ниже, то сложнее, да) с ограничениями по геттерам, разве что.
rock
30.08.2015 04:38Извините, но я не совсем понимаю как связано у вас «сильно вырос как инструмент» и «можно компилить код даже для IE8», хоть, вроде, я и ответственен здесь за обеспечение кроссплатформенной совместимости — читай, полифилы. Код и на момент написания статьи, и сейчас, прекрасно работает как в IE8, так и, например, в IE6 — с точки зрения JavaScript разница между ними минимальна, что нельзя был реализовать тогда — нельзя реализовать и сейчас, например, те же дескрипторы. Разве что до определенного момента (апреля, если не ошибаюсь) полифилы ES5 из
core-js
не были включены вbabel/polyfill
по умолчанию, только ES6+.trikadin
30.08.2015 15:44Меньше багов и больше возможностей. Возможно, да, моё сообщение несколько необдуманное. В целом — я просто хотел выразить согласие с тем, что статья устарела, и сказать, что писать код даже для старых браузеров на ES6+ (с ограничениями, опять же) вполне реально.
VasilioRuzanni
«Полизаполнения»? Серьезно? :D
ph_piter
Вы-таки считаете, что это полифиллы? mattweb.ru/component/k2/item/74-kratko-o-polizapolnenii
VasilioRuzanni
Конечно, «полифиллы» — или же polyfills (без перевода). Но «полизаполнения» очень уж слух/глаза режет. Думаю, я не один такой :)
SelenIT2
На мой взгляд, уж всяко лучше прижившееся заимствование «полифил(л)», чем нелепая и нелогичная механическая полуадаптация чужого слова, вызывающая совершенно не те ассоциации (у меня, например, первая ассоциация с «полизаполнением» — скрипт автоматического заполнения форм, а вовсе не «костыль»/«подпорка» для недостающей системной функциональности).
Не говоря о том, что «полизаполнение» почти невозможно выговорить, а при чтении не сразу понятно, кто тут чего полизал:)
ph_piter
Окей, полифиллы
stas404
Я извиняюсь за вопрос не в тему — хотел поинтересоваться по поводу книги «Exploring ES6» за авторством Axel Rauschmayer.
Не светит ли?
batyrmastyr
Я хоть и не люблю тупую транслитерацию, но полизаполнения это недоперевод. Если уж на то пошло, то лучше выкинуть «поли» (совсем не тот смысл придаёт) и оставить только «заполнитель». Можно ещё из переводов shim на «прокладку» / «компенсатор» покрутить, но уж лучше как SelenIT2 «подпоркой» назвать.
SelenIT2
Да вот и с «заполнителем» сомнения. В англоязычном мире для таких решений сложилась метафора «замазки» или «шпаклевки», которой «заполняют/заделывают щели и выбоины в стене» (получая ровную поверхность, с которой приятно работать). Но у нас, насколько я в курсе, такая метафора вообще не в ходу, у нас, по-моему, недостающую функциональность принято скорее «подпирать костылем». «Прокладка», в принципе, тоже вариант…
MTonly
Как вариант, скриптовая реализация, эмулирующий скрипт или эмуляция.
SelenIT2
Вот да, пожалуй, скрипт-эмулятор вообще идеально попадает в точку. Даже если речь об эмуляции самих скриптов (напр. новых методов Array, не работающих в IE8). Просто «эмуляция», имхо, слегка слишком общо, но тоже может подойти…
batyrmastyr
Наполовину в шутку, наполовину всерьёз предлагаю назвать соломой — только представьте «Вась, ты молодец конечно, но ослику соломки подстелить не судьба?» )