The use of polyfills when writing cross-browser applications

Recently, a funny story happened to me. I made a web project and expanded the capabilities of an existing application that my personnel use in my organization. Everything looked just fine, I was glad that the project was launched, looking forward to letters of thanks.



A few days after the first release, I really began to receive letters. But thanks were not observed in them. Managers, human resources workers, and all those who tried to use my program wrote to me. All of them said that their application does not work correctly.







What is the matter? But the fact is that when I created the project, I tested it in Chrome. But users of this project constantly use Firefox and IE. Working with my application was no exception. In the end, I was completely sad that the project launched a couple of days ago had to be finalized.



As a matter of fact, here polyfills came to my aid.



Polyfills



A polyfill (polyfill or polyfiller) is a piece of code (or a certain plug-in) that implements what the developer expects among standard browser capabilities. Polyfills allow, so to speak, to “smooth out” the irregularities of browser APIs.



In a web environment, polyfills are usually represented by JavaScript code. This code is used to equip legacy browsers with modern features that these browsers do not support.



For example, using polyfill, you can simulate the functionality of the HTML Canvas element in Microsoft Internet Explorer 7. For this, the Silverlight plugin is used. By means of polyfill, support for rem



units of measure in CSS, or the text-shadow attribute, or anything else can be implemented. The reasons why developers do not use exclusively polyfills, without paying attention to the built-in capabilities of browsers, are that the standard capabilities of browsers provide better functionality and higher performance. Own browser implementations of various APIs have more features than polyfills, and they work faster.



Sometimes polyfills are used to solve problems related to the fact that different browsers implement the same features in different ways. Such polyfill interact with some browsers, using their non-standard features, and give other JavaScript programs access to certain mechanisms that meet the standards. It should be noted that such reasons for using polyfills today are no longer as relevant as before. Polyfills were especially prevalent in the days of IE6, Netscape, and NNav, when each browser implemented JavaScript capabilities differently from the others.



Example



I recently published a development guide for an application that converts CSV and Excel files to JSON using JavaScript. Here you can see the finished application.



In order to deal with what we will talk about later, you can either do everything that is discussed in the manual , or clone my repository with the following command:



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





I recommend using VS Code in the process. You can launch the web application locally using the extension for VS Code Live Server .



Let's modify this web application and look at the problems that arise when working with it using different browsers.



Create a polyfill



branch in the repository and switch to it:



 git checkout -b polyfill
      
      





I am going to investigate a situation in which we get data from two or more CSV files, and, after processing the results of requests to the corresponding APIs, we output this data to an HTML table.



▍ Finalization of the project



Create a new CSV file ( team2.csv



) in the root directory of the project, as a result of which there should be two files. Here is the file that I added to the project.



We script.js



file so that it reads data from 2 files and displays all the data in an HTML table. Here is my 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>'        );    }); }
      
      





Now, having copied the page address, open the project in all the browsers that you have. In my case, these were Internet Explorer, Firefox Mozilla, Microsoft Edge, and Google Chrome. It turned out that the application stopped working normally in Internet Explorer and Microsoft Edge. Only headers were displayed there.





Chrome Project Page





Microsoft Edge Project Page



There are no data on the page displayed by some browsers for two reasons:



  1. I used promises and callbacks that not all browsers support. For example, such browsers include IE and Edge.
  2. I used the flat()



    array method to create a new "flat" array from an existing array. This method is not supported by some browsers. Among them, as in the previous case, IE and Edge.


▍Application of polyfills



We fix the problem of promises and callbacks using the Bluebird library. This is a full-blown JS implementation of mechanisms related to promises. The most interesting feature of the Bluebird library is that it allows you to “overclass” other Node modules, processing them so that you can work with them asynchronously. This kind of processing can be applied to code that uses callbacks.



Download the Bluebird library to the page using the appropriate CDN resource. To do this, put the following in the header of the index.html



file (in the head



element):



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





In order to fix the problem regarding the flat()



array method, add the following code to the top of the script.js



file:



 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 });
      
      





Now the application should work in all browsers as expected. Here, for example, is how it now looks in Microsoft Edge.





Refined Project Page in Microsoft Edge



I have deployed this project here . You can experience it.



If you didn’t manage to get the project working, look into my repository .



And here - for example - a couple more polyfills.



 //   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;        }    }; }
      
      





Summary



Polyfills were especially relevant before, but even today they can help in the development of cross-browser web projects. We hope that the example given here allowed those who did not know about polyfill to take a fresh look at the problem of creating sites designed for different browsers.



Dear readers! Do you use polyfill?








All Articles