Polyfill (полифилл) — код, эмулирующий отсутствующую функциональность (API, методы, объекты) в средах, где она не реализована нативно. Polyfill позволяет использовать современные возможности JavaScript, CSS или Web API в старых браузерах и рантаймах. По данным MDN Web Docs, полифиллы являются ключевым инструментом прогрессивного улучшения и обеспечения кросс-браузерной совместимости.
Главное
Polyfill — фрагмент кода (обычно JavaScript), реализующий функциональность, которую среда выполнения не поддерживает нативно. Термин предложен Реми Шарпом в 2009 году как игра слов: Polyfill — аналог шпатлёвки (Polyfilla), заполняющей трещины в стене. Polyfill заполняет пробелы между стандартом и поддержкой в конкретном браузере или рантайме.
Polyfill не изменяет существующий код — он расширяет среду выполнения. Если браузер не поддерживает Array.prototype.includes, полифилл добавляет этот метод в прототип Array до выполнения основного кода. Полифиллы могут эмулировать новые глобальные объекты (Promise, Map, Set, Symbol), статические методы (Array.from, Object.assign) и методы прототипов.
Feature detection — обязательный механизм перед установкой полифилла. Вместо проверки user-agent (какой браузер), следует проверять наличие метода: if (!Array.prototype.includes) { Array.prototype.includes = ... }. Это гарантирует, что полифилл не перезапишет нативную реализацию, если она уже существует. Google Analytics и другие сервисы собирают данные о поддержке API для анализа.
Первые полифиллы появились в эпоху Internet Explorer 6–8 (2005–2009), когда разработчики обнаружили разрыв между стандартами W3C и реализацией в браузерах. Термин ввёл Реми Шарп в 2009 году на конференции BarCamp London. Первым массовым полифиллом стал html5shiv (2009) — библиотека, добавляющая поддержку HTML5-тегов (<section>, <article>, <nav>) в Internet Explorer.
С появлением ES6 (2015) и годового цикла обновлений ECMAScript количество необходимых полифиллов выросло. Каждый год стандарт добавляет новые методы (Array.includes, String.padStart, Object.fromEntries, Promise.allSettled), которые не поддерживаются старыми браузерами. core-js, начатый как es6-shim в 2014, стал универсальным решением. На 2026 год core-js содержит более 5000 модулей полифиллов для ES5–ES2025.
| Категория | Можно полифиллить | Нельзя полифиллить |
|---|---|---|
| Методы прототипов | Array.includes, String.startsWith | — |
| Глобальные объекты | Promise, Map, Set, Symbol | — |
| Статические методы | Object.assign, Array.from | — |
| Синтаксис языка | — | Arrow functions, async/await, class |
| Web API | fetch, IntersectionObserver | Service Worker (требует нативной поддержки) |
Транспиляция преобразует новый синтаксис в старый (const → var, () => {} → function() {}). Polyfill добавляет отсутствующие методы и объекты (Promise, Array.includes). Эти два механизма дополняют друг друга: транспиляция делает код синтаксически совместимым, полифиллы обеспечивают полноту API. Babel + core-js — стандартная комбинация для полной поддержки.
Babel @babel/preset-env с опцией useBuiltIns определяет, какие полифиллы нужны на основе target-браузеров. useBuiltIns: "usage" анализирует, какие API используются в коде, и подключает только нужные полифиллы из core-js. useBuiltIns: "entry" подключает все полифиллы для target-браузеров через единый импорт core-js/stable.
// Проверка наличия и добавление полифилла
if (typeof Array.prototype.includes !== "function") {
Object.defineProperty(Array.prototype, "includes", {
value: function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError("Array.prototype.includes called on null or undefined");
}
var arr = Object(this);
var len = arr.length >>> 0;
if (len === 0) { return false; }
var start = fromIndex | 0;
var k = Math.max(start >= 0 ? start : len + start, 0);
while (k < len) {
if (arr[k] === searchElement) { return true; }
k++;
}
return false;
},
writable: true,
configurable: true,
});
}
// Использование — теперь безопасно в любом браузере
const arr = [1, 2, 3, 4, 5];
console.log(arr.includes(3)); // trueПолифилл для Array.prototype.includes проверяет, определён ли метод в прототипе Array. Если нет — создаёт свойство через Object.defineProperty с флагами writable: true, configurable: true. Реализация следует спецификации ES2016: проверка null/undefined, преобразование в объект, работа с отрицательным fromIndex. После добавления полифилла вызов arr.includes(3) работает во всех браузерах, включая Internet Explorer 11.
core-js — самая полная библиотека полифиллов JavaScript, поддерживающая все stage-4 предложения TC39 (ECMAScript стандарт). core-js вмещает полифиллы для Promise, Symbol, Map, Set, WeakMap, WeakSet, Array методы, String методы, Object методы, Number методы, Math методы, Reflect, globalThis и всех stage-4 proposals. Актуальная версия core-js 3.38+ покрывает ES5–ES2025.
core-js интегрируется с Babel через @babel/preset-env и опцию useBuiltIns. Без этой интеграции разработчику пришлось бы вручную импортировать каждый полифилл: import "core-js/stable/array/includes". @babel/preset-env автоматически добавляет необходимые импорты на основе target-браузеров из .browserslistrc. Это уменьшает размер бандла — подключаются только нужные полифиллы.
Fetch API — один из самых часто полифиллимых Web API. Нативная реализация fetch доступна в Chrome 42+ (2015), Safari 10.1+ (2017), Firefox 39+ (2015), но отсутствует в Internet Explorer и старых WebView. Полифилл whatwg-fetch эмулирует fetch через XMLHttpRequest. Альтернатива — используем isomorphic-fetch (полифилл для Node.js и браузера) или универсальную библиотеку axios, не требующую полифиллов.
// Загрузка полифилла fetch только для старых браузеров
if (typeof self.fetch !== "function") {
import("whatwg-fetch").then(module => {
self.fetch = module.fetch;
console.log("fetch polyfill loaded");
});
}
// Использование fetch (работает и с полифиллом, и с нативным API)
async function loadData() {
try {
const response = await fetch("https://api.example.com/data");
const json = await response.json();
return json;
} catch (error) {
console.error("Failed to load:", error);
}
}Динамический import полифилла fetch через import() гарантирует, что современные браузеры не загрузят лишний код. Полифилл загружается асинхронно и не блокирует основной поток. После загрузки self.fetch заменяет нативную реализацию или добавляет отсутствующую. Это техника прогрессивного enhancement: современные браузеры получают только нативный код, старые — дополнительный полифилл.
// babel.config.js — core-js + preset-env
module.exports = {
presets: [
["@babel/preset-env", {
useBuiltIns: "usage",
corejs: {
version: "3.38",
proposals: true,
},
targets: {
browsers: ["> 0.5%", "not dead", "not op_mini all"],
},
}],
],
};# .browserslistrc — целевые браузеры
> 0.5%
last 2 versions
not dead
not op_mini all
ie >= 11
not ios_saf < 12useBuiltIns: "usage" анализирует код и добавляет только те полифиллы, которые реально используются. corejs.version указывает версию core-js в проекте. targets.browsers определяет минимальный уровень браузеров — чем древнее браузеры, тем больше полифиллов будет подключено. .browserslistrc используется не только Babel, но и Autoprefixer, PostCSS и Stylelint для согласованного таргетинга.
Polyfill.io — сервис (и одноимённая библиотека), динамически определяющий, какие полифиллы нужны браузеру пользователя, и возвращающий только их. Polyfill.io использует заголовок User-Agent для определения версии браузера и подставляет минимальный набор полифиллов. Это уменьшает размер передаваемых данных по сравнению с универсальным бандлом полифиллов.
Подключение Polyfill.io выполняется через <script>-тег перед основным кодом приложения. Сервис анализирует User-Agent и возвращает JavaScript-файл с полифиллами только для этого браузера. Chrome не получит ни одного полифилла, IE 11 получит полный набор. Это оптимальный подход для производительности: современные браузеры не загружают лишний код.
<!-- Polyfill.io: динамическая загрузка -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=Promise%2CArray.prototype.includes%2CObject.assign%2Cfetch"></script>
<!-- Локальная версия Polyfill.io -->
<script src="/js/polyfill.js"></script>
<script>
// feature detection для fetch
if (!self.fetch) {
loadScript("/js/fetch-polyfill.js");
}
</script>Параметр features в URL Polyfill.io указывает, какие полифиллы загружать. Возможные значения: названия методов (Array.prototype.includes), глобальных объектов (Promise), или флаги (es6, es2016). Флаг "default" подключает базовый набор для современного JavaScript. Для production-проектов рекомендуется размещать Polyfill.io на собственном CDN или использовать локальную версию библиотеки для контроля над доступностью.
WebView в мобильных приложениях (Android WebView, WKWebView на iOS) — особая среда для полифиллов. Версия WebView зависит от версии ОС и установленного обновления Chrome System WebView (Android) или WKWebView от iOS Safari. В старых версиях Android (4.4, 5.0) WebView основан на Chromium 30–37 — без поддержки fetch, Promise, IntersectionObserver.
React Native использует JavaScriptCore (iOS) или Hermes (Android) — эти движки реализуют ES6+ по-разному. JavaScriptCore на iOS поддерживает большинство ES6-фич, но может не иметь некоторых stage-3 предложений. Hermes (используемый по умолчанию в React Native 0.70+) поддерживает ограниченный набор ES-стандарта — для него полифиллы обязательны.
// feature detection для WebView
const polyfills = [];
// Promise
if (typeof Promise === "undefined") {
polyfills.push("Promise");
}
// Fetch API
if (typeof self.fetch === "undefined") {
polyfills.push("fetch");
}
// IntersectionObserver (нужен для ленивой загрузки)
if (typeof IntersectionObserver === "undefined") {
polyfills.push("IntersectionObserver");
}
// Динамическая загрузка полифиллов
if (polyfills.length > 0) {
const script = document.createElement("script");
script.src = "https://cdn.polyfill.io/v3/polyfill.min.js"
+ "?features=" + polyfills.join(",");
document.head.appendChild(script);
}Feature detection для WebView проверяет наличие критических API (Promise, fetch, IntersectionObserver) и динамически загружает полифиллы только для отсутствующих. Это гарантирует, что современные WebView (Chrome 100+ на Android 12) не загружают лишний код, а старые WebView (Android 5.0) получают необходимую поддержку.
Часто задаваемые вопросы
React Native на Hermes требует полифиллы для некоторых ES-методов: Array.flat, Array.flatMap, globalThis, TextEncoder. Рекомендуется подключать core-js или react-native-polyfill-globals для продакшен-сборок. JavaScriptCore на iOS поддерживает больше фич, но также может требовать полифиллы для stage-3 предложений.
Полифиллы снижают производительность на 1–5%, так как JavaScript-реализация медленнее нативной C++ реализации в движке. Например, полифил Promise на чистом JS медленнее нативного Promise в V8. Однако для большинства приложений разница незаметна. Для критического кода рекомендуется проверять наличие нативной реализации через feature detection.
Транспиляция преобразует синтаксис: const → var, стрелочные функции → function. Полифилл добавляет новые объекты/методы: Promise, Array.includes, fetch. Транспиляция работает на этапе сборки, полифилл загружается в runtime. Оба механизма необходимы для полной поддержки современного кода в старых средах.
Можно, если target-аудитория использует только современные браузеры (Chrome 90+, Safari 15+, Firefox 90+). Для проектов с поддержкой старых устройств или корпоративных пользователей (Internet Explorer 11 всё ещё используется в госсекторе) полифиллы обязательны. Анализируйте статистику браузеров вашей аудитории через Google Analytics.
core-js в полной сборке весит ~85 КБ (gzip). При использовании useBuiltIns: "usage" в Babel подключаются только нужные полифиллы, что уменьшает размер до 5–30 КБ в зависимости от target-браузеров. Для современных браузеров (Chrome 100+) может не потребоваться ни одного полифилла.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также