Shim

May 20, 2023

A shim, also known as a polyfill or a compatibility layer, is a piece of code that is used to bridge the gap between different programming interfaces. It is used to provide support for APIs, functions, or features that may not be available in a particular version of a web browser or in a certain environment.

Shims are used primarily to provide backward compatibility for older versions of web browsers. They allow developers to write code that uses modern web technologies and still be able to run on older browsers that do not support those technologies. Additionally, shims can provide a consistent API across different browsers, making it easier to write cross-browser compatible code.

Purpose

The purpose of a shim is to provide a layer of abstraction between the application code and the underlying web platform. This abstraction allows the application code to remain independent of the specific environment it is running in, and to take advantage of the latest technologies and features available in modern web platforms.

Shims can also be used to provide a safety net for developers. If a certain feature is not available in a particular browser or environment, the shim can be used to provide a fallback solution that will ensure that the application does not fail or behave unexpectedly.

Usage

Shims can be used for a variety of purposes in web development. Some of the most common use cases for shims include:

1. Browser compatibility

One of the most common use cases for shims is to provide compatibility for older browsers that do not support newer web technologies. For example, the HTML5 canvas API is not supported in Internet Explorer 8 and earlier versions. A shim can be used to provide support for the canvas API in those browsers, allowing developers to write code that works across different browsers.

2. Feature detection

Shims can also be used for feature detection. By detecting whether a certain feature is available in the current environment, the shim can provide a fallback solution if the feature is not available. For example, if the localStorage API is not available in a particular browser, a shim can be used to provide a fallback solution that uses cookies instead.

3. Polyfills

Shims can also be used as polyfills. A polyfill is a piece of code that provides support for a feature that is not yet widely supported by browsers. For example, if the Promise API is not supported in a particular browser, a polyfill can be used to provide support for the Promise API.

4. API standardization

Shims can also be used to provide a consistent API across different browsers. This is particularly useful for APIs that have different implementations in different browsers. By providing a consistent API, developers can write code that works across different browsers without having to worry about the specific implementation details.

Examples

1. addEventListener shim

The addEventListener API is used to attach event listeners to DOM elements. However, this API is not supported in Internet Explorer 8 and earlier versions. A shim can be used to provide support for the addEventListener API in those browsers.

if (!Element.prototype.addEventListener) {
  Element.prototype.addEventListener = function (event, callback) {
    return this.attachEvent('on' + event, callback);
  };
}

This shim checks whether the addEventListener API is available in the current environment. If it is not available, it creates a new method that attaches event listeners using the attachEvent method, which is supported in older versions of Internet Explorer.

2. localStorage shim

The localStorage API is used to store data in the browser. However, this API is not available in all browsers. A shim can be used to provide support for the localStorage API in browsers that do not support it.

if (!window.localStorage) {
  window.localStorage = {
    getItem: function (key) {
      return document.cookie.replace(new RegExp('(?:^|.*;\\s*)' + key.replace(/[\-\.\+\*]/g, '\\
 
amp;') + '\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*'), '$1'); }, setItem: function (key, value) { document.cookie = key + '=' + value + '; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/'; }, removeItem: function (key) { document.cookie = key + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'; } }; } 

This shim checks whether the localStorage API is available in the current environment. If it is not available, it creates a new object that provides methods for getting, setting, and removing data using cookies instead.

3. Promise polyfill

The Promise API is used to handle asynchronous operations in JavaScript. However, this API is not supported in all browsers. A polyfill can be used to provide support for the Promise API.

if (!window.Promise) {
  window.Promise = function (executor) {
    var self = this;

    self.onResolvedCallbacks = [];
    self.onRejectedCallbacks = [];

    function resolve(value) {
      setTimeout(function () {
        self.onResolvedCallbacks.forEach(function (callback) {
          callback(value);
        });
      }, 0);
    }

    function reject(reason) {
      setTimeout(function () {
        self.onRejectedCallbacks.forEach(function (callback) {
          callback(reason);
        });
      }, 0);
    }

    executor(resolve, reject);
  };

  window.Promise.prototype.then = function (onResolved, onRejected) {
    var self = this;

    var promise2 = new Promise(function (resolve, reject) {
      function handle(callback) {
        try {
          var x = callback(self.value);
          resolve(x);
        } catch (e) {
          reject(e);
        }
      }

      if (self.status === 'resolved') {
        handle(onResolved);
      } else if (self.status === 'rejected') {
        handle(onRejected);
      } else {
        self.onResolvedCallbacks.push(function () {
          handle(onResolved);
        });
        self.onRejectedCallbacks.push(function () {
          handle(onRejected);
        });
      }
    });

    return promise2;
  };
}

This polyfill checks whether the Promise API is available in the current environment. If it is not available, it creates a new Promise constructor and then method that provide support for handling asynchronous operations using callbacks.