Полифилы js что это
Перейти к содержимому

Полифилы js что это

  • автор:

Полифилы

JavaScript – динамично развивающийся язык программирования. Регулярно появляются предложения о добавлении в JS новых возможностей, они анализируются, и, если предложения одобряются, то описания новых возможностей языка переносятся в черновик https://tc39.github.io/ecma262/, а затем публикуются в спецификации.

Разработчики JavaScript-движков сами решают, какие предложения реализовывать в первую очередь. Они могут заранее добавить в браузеры поддержку функций, которые всё ещё находятся в черновике, и отложить разработку функций, которые уже перенесены в спецификацию, потому что они менее интересны разработчикам или более сложные в реализации.

Таким образом, довольно часто реализуется только часть стандарта.

Можно проверить текущее состояние поддержки различных возможностей JavaScript на странице https://compat-table.github.io/compat-table/es6/ (нам ещё предстоит изучить многое из этого списка).

Babel

Когда мы используем современные возможности JavaScript, некоторые движки могут не поддерживать их. Как было сказано выше, не везде реализованы все функции.

И тут приходит на помощь Babel.

Babel – это транспилер. Он переписывает современный JavaScript-код в предыдущий стандарт.

На самом деле, есть две части Babel:

  1. Во-первых, транспилер, который переписывает код. Разработчик запускает Babel на своём компьютере. Он переписывает код в старый стандарт. И после этого код отправляется на сайт. Современные сборщики проектов, такие как webpack или brunch, предоставляют возможность запускать транспилер автоматически после каждого изменения кода, что позволяет экономить время.
  2. Во-вторых, полифил. Новые возможности языка могут включать встроенные функции и синтаксические конструкции. Транспилер переписывает код, преобразовывая новые синтаксические конструкции в старые. Но что касается новых встроенных функций, нам нужно их как-то реализовать. JavaScript является высокодинамичным языком, скрипты могут добавлять/изменять любые функции, чтобы они вели себя в соответствии с современным стандартом. Термин «полифил» означает, что скрипт «заполняет» пробелы и добавляет современные функции. Два интересных хранилища полифилов:
    • core js поддерживает много функций, можно подключать только нужные.
    • polyfill.io – сервис, который автоматически создаёт скрипт с полифилом в зависимости от необходимых функций и браузера пользователя.

Таким образом, чтобы современные функции поддерживались в старых движках, нам надо установить транспилер и добавить полифил.

Примеры в учебнике

Большинство примеров можно запустить «на месте», как этот:

alert('Нажмите кнопку "Play" в крайнем правом углу, чтобы запустить пример');

Примеры, в которых используются современные возможности JS, будут работать, если ваш браузер их поддерживает.

Google Chrome обычно поддерживает современные функции, можно запускать новейшие примеры без каких-либо транспилеров, но и другие современные браузеры тоже хорошо работают.

Современный DOM: полифилы

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

В старых IE, особенно в IE8 и ниже, ряд стандартных DOM-свойств не поддерживаются или поддерживаются плохо.

Если говорить о современных браузерах, то они тоже не все идут «в ногу», всегда какие-то современные возможности реализуются сначала в одном, потом в другом.

Но это не значит, что нужно ориентироваться на самый старый браузер из поддерживаемых!

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

Полифилы

«Полифил» (англ. polyfill) – это библиотека, которая добавляет в старые браузеры поддержку возможностей, которые в современных браузерах являются встроенными.

Один полифил мы уже видели, когда изучали собственно JavaScript – это библиотека ES5 shim. Если её подключить, то в IE8- начинают работать многие возможности ES5. Работает она через модификацию стандартных объектов и их прототипов. Это типично для полифилов.

В работе с DOM несовместимостей гораздо больше, как и способов их обхода.

Что делает полифил?

Для примера добавим в DOM поддержку свойства firstElementChild , если её нет. Здесь речь, конечно, об IE8, в других браузерах оно и так поддерживается, но пример типовой.

Вот код для такого полифила:

if (document.documentElement.firstElementChild === undefined) < // (1) Object.defineProperty(Element.prototype, 'firstElementChild', < // (2) get: function() < var el = this.firstChild; do < if (el.nodeType === 1) < return el; >el = el.nextSibling; > while (el); return null; > >); >

Если этот код запустить, то firstElementChild появится у всех элементов в IE8.

Общий вид этого полифила довольно типичен. Обычно полифил состоит из двух частей:

  1. Проверка, есть ли встроенная возможность.
  2. Эмуляция, если её нет.

Проверка встроенного свойства

Для проверки встроенной поддержки firstElementChild мы можем просто обратиться к document.documentElement.firstElementChild .

Если DOM-свойство firstElementChild поддерживается, то его значение не может быть undefined . Если детей нет – свойство равно null , но не undefined .

alert( document.head.previousSibling ); // null, поддержка есть alert( document.head.blabla ); // undefined, поддержки нет

За счёт этого работает проверка в первой строке полифила.

Важная тонкость – элемент, который мы тестируем, должен по стандарту поддерживать такое свойство.

Попытаемся, к примеру, проверить «поддержку» свойства value . У input оно есть, у div такого свойства нет:

var div = document.createElement('div'); var input = document.createElement('input'); alert( input.value ); // пустая строка, поддержка есть alert( div.value ); // undefined, поддержки нет

Поддержка значений свойств

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

Например, нам интересно, поддерживает ли браузер . То есть, понятно, что свойство type у input , в целом, поддерживается, а вот конкретный тип ?

Для этого можно создать с таким type и посмотреть, подействовал ли он.

    
  1. Первый input имеет type=»radio» . Этот тип точно поддерживается, поэтому input.type имеет значение «radio» , как и указано.
  2. Второй input имеет type=»no-such-type» . В качестве типа, для примера, специально указано заведомо неподдерживаемое значение. При этом input.type равен «text» , таково значение по умолчанию. Мы можем прочитать его и увидеть, что поддержки нет.

Эта проверка работает, так как хоть в HTML-атрибут type и можно присвоить любую строку, но DOM-свойство type по стандарту хранит реальный тип input’а .

Добавляем поддержку свойства

Если мы осуществили проверку и видим, что встроенной поддержки нет – полифил должен её добавить.

Для этого вспомним, что DOM элементы описываются соответствующими JS-классами.

Они наследуют, как мы видели ранее, от HTMLElement, который является общим родительским классом для HTML-элементов.

А HTMLElement , в свою очередь, наследует от Element, который является общим родителем не только для HTML, но и для других DOM-структур, например для XML и SVG.

Для добавления нужной возможности берётся правильный класс и модифицируется его prototype .

Например, можно добавить всем элементам в прототип функцию:

Element.prototype.sayHi = function() < alert( "Привет от " + this ); >document.body.sayHi(); // Привет от [object HTMLBodyElement]

Сложнее – добавить свойство, но это тоже возможно, через Object.defineProperty :

Object.defineProperty(Element.prototype, 'lowerTag', < get: function() < return this.tagName.toLowerCase(); >>); alert( document.body.lowerTag ); // body

Геттер-сеттер и IE8

В IE8 современные методы для работы со свойствами, такие как Object.defineProperty, Object.getOwnPropertyDescriptor и другие не поддерживаются для произвольных объектов, но отлично работают для DOM-элементов.

Чем полифилы и пользуются, «добавляя» в IE8 многие из современных методов DOM.

Какова поддержка свойства?

А нужен ли вообще полифил? Какие браузеры поддерживают интересное нам свойство или метод?

Зачастую такая информация есть в справочнике MDN, например для метода remove() : https://developer.mozilla.org/en-US/docs/Web/API/ChildNode.remove – табличка совместимости внизу.

Итого

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

Многие из них легко полифилятся добавлением на страницу соответствующих библиотек.

Для поиска полифила обычно достаточно ввести в поисковике «polyfill» , и нужное свойство либо метод. Как правило, полифилы идут в виде коллекций скриптов.

Полифилы хороши тем, что мы просто подключаем их и используем везде современный DOM/JS, а когда старые браузеры окончательно отомрут – просто выкинем полифил, без изменения кода.

Типичная схема работы полифила DOM-свойства или метода:

  • Создаётся элемент, который его, в теории, должен поддерживать.
  • Соответствующее свойство сравнивается с undefined .
  • Если его нет – модифицируется прототип, обычно это Element.prototype – в него дописываются новые геттеры и функции.

Другие полифилы сделать сложнее. Например, полифил, который хочет добавить в браузер поддержку элементов вида , может найти все такие элементы на странице и обработать их, меняя внешний вид и работу через JavaScript. Это возможно. Но если уже существующему поменять type на range – полифил не «подхватит» его автоматически.

Описанная ситуация нормальна. Не всегда полифил обеспечивает идеальную поддержку наравне с родными свойствами. Но если мы не собираемся так делать, то подобный полифил вполне подойдёт.

Один из лучших сервисов для полифилов: polyfill.io. Он даёт возможность вставлять на свою страницу скрипт с запросом к сервису, например:

При запросе сервис анализирует заголовки, понимает, какая версия какого браузера к нему обратилась и возвращает скрипт-полифил, добавляющий в браузер возможности, которых там нет. В параметре features можно указать, какие именно возможности нужны, в примере выше это функции стандарта ES6. Подробнее – см. примеры и список возможностей.

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

  • https://github.com/jonathantneal/polyfill – ES5 вместе с DOM
  • https://github.com/termi/ES5-DOM-SHIM – ES5 вместе с DOM
  • https://github.com/inexorabletash/polyfill – ES5+ вместе с DOM

Более мелкие библиотеки, а также коллекции ссылок на них:

  • http://compatibility.shwups-cms.ch/en/polyfills/
  • http://html5please.com/#polyfill
  • https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills

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

Задачи

Полифилл для matches

важность: 5

Метод elem.matches(css) в некоторых старых браузерах поддерживается под старым именем matchesSelector или с префиксами, то есть: webkitMatchesSelector (старый Chrome, Safari), mozMatchesSelector (старый Firefox) или Element.prototype.msMatchesSelector (старый IE).

Создайте полифилл, который гарантирует стандартный синтаксис elem.matches(css) для всех браузеров.

Код для полифилла здесь особенно прост.

Реализовывать ничего не надо, просто записать нужный метод в Element.prototype.matches , если его там нет:

(function() < // проверяем поддержку if (!Element.prototype.matches) < // определяем свойство Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector; >>)();

полифил js что это

Polyfill (полифил) в JavaScript — это код, написанный на JavaScript, который позволяет использовать новые функции языка, даже если они не поддерживаются старыми или устаревшими браузерами.

Например, если новая версия JavaScript включает новый метод массива, но старый браузер не поддерживает этот метод, вы можете написать полифил, который добавит этот метод в объект массива. Таким образом, вы можете использовать новый метод во всех браузерах, включая старые.

Полифилы — это часто используемый инструмент в веб-разработке, потому что они позволяют использовать новые функции языка, не отказываясь от поддержки старых браузеров.

Использование полифиллов при написании кросс-браузерных приложений

Недавно со мной случилась одна весёлая история. Я сделал веб-проект и расширил возможности уже существующего приложения, которым в моей организации пользуются кадровики. Всё выглядело просто отлично, я радовался тому, что проект был запущен, с нетерпением ожидая благодарственных писем.

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

В чём же дело? А дело в том, что я, создавая проект, тестировал его в Chrome. Но пользователи этого проекта постоянно применяют Firefox и IE. Работа с моим приложением не стала исключением. Мне, в итоге, было совсем невесело от того, что проект, запущенный пару дней назад, надо было дорабатывать.

Собственно говоря, тут мне на помощь и пришли полифиллы.

Полифиллы

Полифилл (polyfill или polyfiller) — это фрагмент кода (или некий плагин), реализующий то, наличия чего разработчик ожидает среди стандартных возможностей браузера. Полифиллы позволяют, так сказать, «сгладить» неровности браузерных API.

В веб-среде полифиллы обычно представлены JavaScript-кодом. Этот код используется для оснащения устаревших браузеров современными возможностями, которые эти браузеры не поддерживают.

Например, с помощью полифилла можно сымитировать функционал HTML-элемента Canvas в Microsoft Internet Explorer 7. Для этого применяется плагин Silverlight. Средствами полифилла может быть реализована поддержка единиц измерения rem в CSS, или атрибута text-shadow, или чего угодно другого. Причины, по которым разработчики не пользуются исключительно полифиллами, не обращая внимание на встроенные возможности браузеров, заключаются в том, что стандартные возможности браузеров обеспечивают более качественный функционал и более высокую производительность. Собственные браузерные реализации различных API обладают более широкими возможностями, чем полифиллы, да и работают быстрее.

Иногда полифиллы используются для решения проблем, связанных с тем, что различные браузеры по-разному реализуют одни и те же возможности. Подобные полифиллы взаимодействуют с некоторыми браузерами, используя их нестандартные особенности, и дают другим JavaScript-программам доступ к определённым механизмам, соответствующий стандартам. Надо отметить, что подобные причины использования полифиллов сегодня уже не так актуальны, как раньше. Особую распространённость полифиллы имели во времена IE6, Netscape и NNav, когда каждый браузер реализовывал возможности JavaScript не так, как другие.

Пример

Недавно я опубликовал руководство по разработке приложения, конвертирующего CSV и Excel-файлы в JSON с помощью JavaScript. Здесь можно посмотреть на готовое приложение.

Для того чтобы разобраться с тем, о чём мы будем говорить дальше, вы можете либо сделать всё то, о чём идёт речь в руководстве, либо клонировать мой репозиторий следующей командой:

git clone https://github.com/YannMjl/jsdemo-read-cvs-xls-json cd jsdemo-read-cvs-xls-json

Рекомендую в процессе работы пользоваться VS Code. Запустить веб-приложение можно локально, с использованием расширения для VS Code Live Server.

Давайте модифицируем это веб-приложение и посмотрим на проблемы, которые возникают при работе с ним с использованием разных браузеров.

Создадим в репозитории ветку polyfill и переключимся на неё:

git checkout -b polyfill

Я собираюсь исследовать ситуацию, в которой мы получаем данные из двух или большего количества CSV-файлов, и, после завершения обработки результатов запросов к соответствующим API, выводим эти данные в HTML-таблицу.

▍Доработка проекта

Создадим в корневой директории проекта новый CSV-файл ( team2.csv ), в результате чего там должно оказаться два файла. Вот файл, который я добавил в проект.

Модифицируем файл script.js так, чтобы он читал бы данные из 2 файлов и выводил бы все данные в HTML-таблицу. Вот мой script.js :

Теперь, скопировав адрес страницы, откройте проект во всех браузерах, которые у вас есть. В моём случае это были Internet Explorer, Firefox Mozilla, Microsoft Edge и Google Chrome. Оказалось, что приложение перестало нормально работать в Internet Explorer и Microsoft Edge. Там выводились только заголовки.

Страница проекта в Chrome

Страница проекта в Microsoft Edge

У того, что на странице, выводимой некоторыми браузерами, нет данных, две причины:

  1. Я пользовался промисами и коллбэками, которые поддерживают не все браузеры. Например, среди таких браузеров — IE и Edge.
  2. Я пользовался методом массивов flat() для того, чтобы создать из существующего массива новый «плоский» массив. Этот метод не поддерживается некоторыми браузерами. Среди них, как и в предыдущем случае, IE и Edge.

▍Применение полифиллов

Исправим проблему промисов и коллбэков, воспользовавшись библиотекой Bluebird. Это — полномасштабная JS-реализация механизмов, связанных с промисами. Самая интересная особенность библиотеки Bluebird заключается в том, что она позволяет «промисифицировать» другие Node-модули, обрабатывая их так, чтобы с ними можно было бы работать асинхронно. Такую обработку можно применить к коду, в котором используются коллбэки.

Загрузим библиотеку Bluebird на страницу, воспользовавшись соответствующим CDN-ресурсом. Для этого разместим в заголовке файла index.html (в элементе head ) следующее:

Для того чтобы исправить проблему, касающуюся метода массивов flat() , добавим в верхнюю часть файла script.js следующий код:

Object.defineProperty(Array.prototype, 'flat', < value: function (depth) < depth = 1; return this.reduce( function (flat, toFlatten) < return flat.concat((Array.isArray(toFlatten) && (depth >1)) ? toFlatten.flat(depth - 1) : toFlatten); >, [] ); >, configurable: true >);

Теперь приложение должно работать во всех браузерах так, как ожидается. Вот, например, как оно теперь выглядит в Microsoft Edge.

Страница доработанного проекта в Microsoft Edge

Я развернул этот проект здесь. Можете его испытать.

Если у вас не получилось добиться работоспособности проекта — загляните в мой репозиторий.

А вот — для примера — ещё пара полифиллов.

// полифилл для String.prototype.startsWith() if (!String.prototype.startsWith) < Object.defineProperty(String.prototype, 'startsWith', < value: function (search, rawPos) < pos = rawPos >0 ? rawPos | 0 : 0; return this.substring(pos, pos + search.length) === search; > >); > // полифилл для String.prototype.includes() if (!String.prototype.includes) < String.prototype.includes = function (search, start) < 'use strict'; if (typeof start !== 'number') < start = 0; >if (start + search.length > this.length) < return false; >else < return this.indexOf(search, start) !== -1; >>; >

Итоги

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

Уважаемые читатели! Пользуетесь ли вы полифиллами?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *