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

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

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



В чём же дело? А дело в том, что я, создавая проект, тестировал его в 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:

// ********************************************************************
// Глобальные переменные                                              *
// объявим глобальные переменные, которые будут использоваться в коде *
// ********************************************************************
var csv_file_API_1 = "./UsersSample.csv";
var csv_file_API_2 = "./team2.csv";
var APIs_array = [csv_file_API_1, csv_file_API_2];

// Выполняем некие действия при загрузке страницы
$(document).ready(function () {

    $("#headerTitle").hide(300).show(1500);

    makeAPICalls();

}); // end: document.ready()

function makeAPICalls() {

    // Массив, который будет содержать обращения к API
    var calls = [];

    // Передача API для CSV-файлов коллбэкам
    APIs_array.forEach(function (csv_file_API) {

        // Помещение промиса в массив вызовов
        calls.push(new Promise(function (resolve, reject) {

            // Выполнение вызова API с использованием AJAX
            $.ajax({

                type: "GET",

                url: csv_file_API,

                dataType: "text",

                cache: false,

                error: function (e) {
                    alert("An error occurred while processing API calls");
                    console.log("API call Failed: ", e);
                    reject(e);
                },

                success: function (data) {

                    var jsonData = $.csv.toObjects(data);

                    console.log(jsonData);

                    resolve(jsonData);
                } // end: обработка данных при успешном обращении к API

            }); // end: AJAX-вызов

        })); // end: добавление данных при вызове промисов

    }); // end: обход массива API


    // После завершения всех обращений к API
    Promise.all(calls).then(function (data) {

        // объединим все данные
        var flatData = data.map(function (item) {
            return item;
        }).flat();

        console.log(flatData);

        dislayData(flatData);
    });

}

function dislayData(data) {
    
    $.each(data, function (index, value) {

        $('#showCSV').append(

            '<li class="list-group-item d-flex justify-content-between align-items-center">' +

                '<span style="width: 15%; font-size: 1rem; font-weight: bold; color: #37474F">' +
                    value['FIRST NAME'] +
                '</span>' +

                '<span style="width: 15%; font-size: 1rem;  color: #37474F">' +
                    value['LAST NAME'] +
                '</span>' +

                '<span class="badge warning-color-dark badge-pill">' +
                    value['PHONE NUMBER'] +
                '</span>' +

                '<span class="badge success-color-dark badge-pill">' +
                    value['EMAIL ADDRESS'] +
                '</span>' +

                '<span class="badge badge-primary badge-pill">' +
                    value.CITY +
                '</span>' +

                '<span class="badge badge-primary badge-pill">' +
                    value.STATE +
                '</span>' +

            '</li>'
        );

    });
}

Теперь, скопировав адрес страницы, откройте проект во всех браузерах, которые у вас есть. В моём случае это были 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) следующее:

<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.7.0/bluebird.min.js"></script>

Для того чтобы исправить проблему, касающуюся метода массивов 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;
        }
    };
}

Итоги


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

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


RUVDS.com
1 481,74
RUVDS – хостинг VDS/VPS серверов
Поделиться публикацией

Похожие публикации

Комментарии 31

    +1
    Буду краток (с).
    На дворе 2020, не используйте полифилы.
    Если что-то работает в хроме, но не работает в ФФ хотя бы в найтли (или наоборот) — значит фича пока сырая, глюкавая и будет дорабатываться.
    Если юзерам нужен ИЕ, то скорее всего у них ХР. Подумайте, нужны ли в 2020 вам такие юзеры. Если даже нужны — пересаживайте их на ESR-версии хрома/ФФ/оперы, там хотя бы асинки работают и большинство из нужных фич.
    Полифилы мало того что раздувают ваш бундль, они ещё часто тормозят всех. JS полифил всегда будет выполняться медленнее, чем нативная реализация того же в браузере.
    На крайний случай делайте две сборки — нормальную и легаси с полифилами. Vue например умеет такое «из коробки», но не всем так повезло.
      +5
      Подумайте, нужны ли в 2020 вам такие юзеры.

      Вот у нас бизнес подумал и сказал, что нужны. Заметную часть доходов приносят пользователи IE в b2b сфере у многих, насколько я знаю.

        0
        А у вас бизнес какие-либо бизнес-метрики снимал с этих юзеров? РОИ там, нагрузка на техподдержку, затраты на тестирование для старых ИЕ, вот это вот всё? Проблема ведь не только в том, что там браузер старый, там скорее всего и комп очень старый (медленный проц, мало ОЗУ). Оно и так еле шевелится, а если туда ещё и полифилов напихать — то по факту приложение запускается, но сколько-нибудь нормально не работает.
          0

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

        +2
        А как быть с пользователями, у которых старый Хром 49, потому что они сидят на каком-нибудь Android 5 или 6 и выходят в интернет со стандартного встроенного браузера «Браузер» или «Интернет»? И их, к сожалению, далеко не 1% пользователей.
          +1
          Ну хром 49 очень далеко ушёл по сравнению с ИЕ9 (ХР), по крайней мере промисы и let/const понимает.
          +3
          раздувают ваш бундль, они ещё часто тормозят всех

          Мы используем такой подход: современные браузеры не тормозим, старые и так медленные.
          Первым идёт небольшой скрипт который проверяет фичу и синхронно подключает скрипт полифила.
          !window.Promise && document.write('<script src="путь"></script>')

          В итоге новый браузер пробегает десяток if и быстро работает, старые браузеры ждут пачки полифилов.

          Правда это не работает с async\await и другим новым синтаксисом, но тут мы планируем собирать два бандла.
            +4
            Если юзерам нужен ИЕ, то скорее всего у них ХР. Подумайте, нужны ли в 2020 вам такие юзеры.


            Ушел пересаживать тысячу-другую своих бухгалтеров и юристов на Линукс, пришла команда из хабра.
              +1
              Рекомендую сначала забрать счёты:)
              +2
              Пользователи с IE в 2020 году очень даже часто встречаются. И не только c XP. Уже давно с семёркой, как минимум.
              А сидят они в IE не по своей прихоти или нежелании переходить на другие браузеры. Основная часть этих пользователей работает или в банковской сфере или работают с банками (или с госструктурами). Он поддерживает нужный тип шифрования. Для этого же браузера пишут специальные расширения для работы. Кроме того, в таких организациях очень не любят что-то менять, если и так хорошо работает.
              В части, что полифилы медленнее нативной реализации, согласен, но, когда нет выбора, то без них не обойтись.
                +2
                Кроме того, в таких организациях очень не любят что-то менять, если и так хорошо работает

                В том-то и дело, что работает плохо. Explorer устаревший и самый небезопасный браузер и ничего хорошего там нет. Сидят на нем не от хорошей жизни, и я не понимаю, зачем оправдывать этот старый хлам.

                  0
                  Я не оправдываю. На счёт «работает хорошо», я имел в виду про налаженный процесс, а не про работу самого браузера.
                  По правде говоря, я и сам не понимаю этого требования на счёт IE. Нормальная система должна работать во всех браузерах. Вот, поэтому, там, где невозможно использовать браузеры актуальной версии или поддерживающие стандартные функции и приходится использовать полифилы (как по мне, частный случай «костылей»).
                  0
                  Это какие такие банки в 2020 требуют ИЕ? Мне кажется лет 5 как вымерли.
                    0
                    Многие. Не скажу о глобальной статистике, но из известных мне — около 85%
                      +1
                      Два крупнейших (зелёный и «хочу купить») не требуют.
                      Решения на основе BSS, которые те самые 85%, тоже давно не требуют именно ИЕ.
                    0
                    в таких организациях очень не любят что-то менять

                    Ну вот, вот настоящая причина. Вон выше xitt 20 лет назад освоил администрирование ХР, и теперь все его «тысячи-другие бухгалтеров и юристов» должны страдать.
                    Ну это его проблемы, а речь про разработчиков. Под ИЕ мало просто поставить полифилы, там слишком много всего надо тащить. Вы не можете использовать допустим нативные мультимедиа АПИ напрямую, вы должны брать либу, которая их оборачивает (и тормозит на нормальных браузерах) и тянет флэш для ИЕ. И так куда ни плюнь. А потом всё это нужно тестировать, в том числе в ИЕ. Со своими тысячами бухгалтеров такие как товарищ выше пусть разбираются сами, но почему миллионы разработчиков должны страдать?
                      0

                      Разработчик волен выбирать поддерживать ему ИЕ и ко или нет. Есть проекты, где даже в вакансиях выдают за свой плюс: "ИЕ не поддерживаем", а крепостное право отменили. Более того, можно даже свой бизнес открыть, если никак не можешь найти проект, где бизнес считает выгодным не поддерживать ИЕ.


                      А так большинство разработчиков поддерживают ИЕ, потому что это входит в условия их работы, они так договорились с работодателем. Уж что-что, а не разу не слышал даже, чтобы поддержка ИЕ появилась в проекте, чтоб пришёл начальник и сказал "ребята, с сегодняшнего дня мы поддерживаем ИЕ" (вернее в третьем тысячелетии ни разу не слышал :) )

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

                  Да, пользуюсь. Давеча было два юзкейса:


                  1. <dialog> polyfill (caniuse)
                  2. :focus-visible polyfill (caniuse)

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


                  Мне обе фичи очень нравятся: диалоги — своей семантичностью и поддержкой нескольких плюшек (form method=dialog, showModal(), ::backdrop), а :focus-visible — возможностью сделать ненавязчивый focus ring, включающийся только при работе с клавиатуры.

                    +1
                    Что касается полифилов. То лучше использовать webpack, который будет компилировать ваш ESNext to ES5. А уже скомпилированный бандл подключать в приложение.

                    По крайней мере проблему flat и Promise вы бы точно решили.
                      0

                      Просто компиляция в ES5, увы ещё не обеспечивает полифиллы

                      0
                      ИМХО, способ описанный в статье — путь в никуда.
                      Наиболее адекватное найденное решение на 2019 год — www.npmjs.com/package/webpack-polyfill-injector
                      Оно конечно не идеально, но на порядок лучше чем искать и подключать необходимые полифиллы ручками из разных источников.
                        0
                        Тестировать достаточно всегда только в IE — если в нем нормально заработает — будет работать везде )
                          +2

                          Неправда. У IE есть то, что не заработает в других браузерах.

                            0
                            Конечно же речь не про специально написанное для IE.
                          +1
                          Скажите пожалуйста те, кто работает под IE и прочем старье и топит за его поддержку, что быстрее и дешевле: пересадить клиента/сотрудника на хром/оперу/фф или выделять десятки часов в месяц и серьезные деньги на разработку, тестирование и поддержку всего этого добра под IE. Я просто хочу увидеть аргументы, почему не пересадить за современный брауз, а продолжать топить за IE. Напишите, если не трудно.

                          Я просто хочу понять насколько сложно реализовать все эти вещи, которые у вас «только под ИЕ» в других браузерах. И что дешевле и выгоднее, ведь прогресс идёт, и с каждым месяцем всё сложнее и сложнее становится его поддерживать и нагружать сайт этим огромным оверхедом полифиллов, бабелей и прочим хламом.

                          Как будто пересадить человека за другой более современный, быстрый и красивый браузер это так сложно (как написали выше), уверен, что они сами не рады мучиться в этом ИЕ на работе и с радостью перешли бы.
                            0

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

                              0
                              Пусть даже так. Что дороже: выгода с этих пары процентов или разработка/тестирование/поддержка ИЕ? Вопрос к менеджерам. Кто-нибудь считал, как выше заметили расходы разработчиков (затраченное время, нервы) и компании (деньги) на поддержку легаси браузеров?

                              Просто приведу пример одного из давних проектов, ставят задачу новый сайт с 0 со всеми фишечками, компонентами и тд. Делаем за пару месяцев. Потом говорят надо ИЕ 11. Ещё пару месяцев натягивали/полифилили/***лись ради пары процентов ИЕшников. И я отчетливо могу сказать, так как в курсе аналитики по покупателям (не по просмотрам, а именно по покупателям, а их ровным счетом 0 было), что оно того не стоило.
                              0
                              Однажды я работал в одной биллинговой конторе. Не суть имя конторы. Так вот. Софт у них был написан еще в начале 2000-х. Причем фронт был заточен только под IE. Причем, под IE 6-7 версии. На 8-ке уже глючило. Софт не маленький и за эти годы было написанно тонные кода.

                              Когда я пришел туда, и копнул код. Я был в ужасе. Конечно я пришел с предложением переписать код, как многие до меня. Так как оддерживать сие — боль. Да и о новых фишках можно было и не думать.

                              И ответ топ менеджмента — Дима, у нас нет бюджета и времени на переписание фронта. Мы не можем выделить команду на полтора два года, для этого. Да и в чем смысл для нас? Клиенты покупают, мы продаем — все овольны. Какой профит принесет переписанный фронт допустим на Реакт?

                              И если подумать — а профита особо и нет для клиента. Увы.

                              Так что не все зависит от программистов. У него свои рамки и приходится выкручиваться и саппортить ненависный IE.
                                0

                                Когда менеджмент топит (а топит обычно только менеджмент в случае публичного продукта) за поддержку IE подразумевается, что они считают прибыльность его поддержки, включая репутационный ущерб от отказа поддерживать клиентов, которые иной раз десятилетия лояльны компании.

                                  0

                                  Сказано красиво, но иной раз кажется что это решение основано не на учете всех факторов, а на обычном "так исторически сложилось, если что-то поменять и оно сломается, кто за это отвечать будет?"


                                  Вот поэтому такая ситуация и есть, ждем пока случится какой-то волшебный скачок, как это вышло в истории про IE6 и Youtube.


                                  P.S. особой сложности добавляет здесь то, что IE11 – это последняя версия браузера вообще. То есть если раньше разговор шел о том, чтобы убрать старые версии из поддержки и оставить только новые, то теперь надо убрать браузер из поддержки целиком. А на это сложнее уговорить.

                                    +1

                                    Может по разному бывает, но на проектах, на которых я работал в последние годы, доля ИЕ мониторится и где-то раз в полгода вопрос о целесообразности дальнейшей поддержки поднимается. В смысле доходит до руководства. Разработчики и QA постоянно поминают IE "добрым, тихим словом".


                                    Я бы не сказал, что сложнее уговорить: аргументы одни и те же у сторон в разговорах, как о том, что дропнуть поддержку 9 и 10, так и 11. Тут скорее оценка вероятности, что клиенты обновятся другая.

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

                              Самое читаемое