How to polyfill JavaScript fetch function for Internet Explorer
Tags: javascript, webdev, tutorial
Published: 2020-09-07 07:54:10

I love using `fetch` API for my personal projects. When using Babel and working on React project, ES6 syntax gets transpiled and polyfilled automatically on build time. But what we need to do when we want to use `fetch` API on a simple project that doesn't use Babel or Webpack? We need to manually polyfill it, and make sure the additional polyfills do not affect website performance.

>A polyfill is a piece of code (usually JavaScript on the Web) used to provide modern functionality on older browsers that do not natively support it.

## Why use "fetch"?

Before `fetch` API was introduced, creating HTTP requests using `XMLHttpRequest` was complicated and the syntax was not clean and straightforward.

```js
var xhr = new XMLHttpRequest();

xhr.open("GET", "https://path/to/api.endpoint");

xhr.send();

xhr.onload = function() {
  // Handle response
};

xhr.onprogress = function(event) {
  // Handle progress
};

xhr.onerror = function() {
  // Handle error
};
```

Yeah, that is a lot of boilerplate code separated into multiple class methods and event handlers.

There were also some JavaScript plugins and jQuery (ajax) functions that act as a wrapper around `XMLHttpRequest` to simplify it and improve the syntax, but there were no official API improvements until ES6 `fetch` API.

## Fetch API

Fetch API allows us to make HTTP requests using much simpler and straightforward JavaScript syntax to send and receive data, and handle any event using  JavaScript promises.

```js
fetch("https://path/to/api.endpoint")
  .then(handleResponse)
  .catch(handleFallback);
```

Looks simple enough, right?

This improved syntax made the whole functionality more accessible and developer-friendly. Although `fetch` browser support sits at comfortable 95%, we can easily polyfill it so even more browsers support it.

## Polyfilling fetch for Internet Explorer

We don't want to just add the polyfill to project so it loads for all browsers (including those that support fetch natively). Let's load the polyfill dynamically so extra JavaScript is loaded only if it's required.

For `fetch` to work on Internet Explorer, we need to add two polyfills:
* Promise polyfill - remember, `fetch` uses promises
* Fetch polyfill

```js
// Detect if user is on IE browser
 var isIE = !!window.MSInputMethodContext && !!document.documentMode;

    if (isIE) {
       // Create Promise polyfill script tag
        var promiseScript = document.createElement("script");
        promiseScript.type = "text/javascript";
        promiseScript.src =
            "https://cdn.jsdelivr.net/npm/promise-polyfill@8.1.3/dist/polyfill.min.js";

      // Create Fetch polyfill script tag
        var fetchScript = document.createElement("script");
        fetchScript.type = "text/javascript";
        fetchScript.src =
            "https://cdn.jsdelivr.net/npm/whatwg-fetch@3.4.0/dist/fetch.umd.min.js";

      // Add polyfills to head element
        document.head.appendChild(promiseScript);
        document.head.appendChild(fetchScript);

      // Wait for the polyfills to load and run the function. 
      // We could have done this differently, 
      // but I've found it to work well for my use-cases
        setTimeout(function () {
            window
                .fetch("https://path/to/api.endpoint")
                .then(handleResponse)
                .catch(handleErrors);
        }, 1000);
    } else {
      // If fetch is supported, just run the fetch function
        fetch("https://path/to/api.endpoint")
                .then(handleResponse)
                .catch(handleErrors);
    }
```

And that is it. If user is using Internet Explorer, `fetch` function will be added to global `window` object and be used as `window.fetch()`.

## Conclusion

I've used this method to load articles from DEV on my [personal website](https://codeadrian.github.io/blog/) using `fetch` and it works as expected. This was really simple to implement and I was happy with the final results. I was also happy that I'm not loading the polyfills if they're not needed.

**Note:** Also feel free to leave a comment on how I can improve my code to replace `setTimeout` function and make sure that this part of the code waits until polyfill becomes available.

<hr/>

These articles are fueled by coffee. So if you enjoy my work and found it useful, consider buying me a coffee! I would really appreciate it.

<a href="https://www.buymeacoffee.com/ubnZ8GgDJ" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-red.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>

Thank you for taking the time to read this post. If you've found this useful, please give it a ❤️ or 🦄, share and comment.