Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promise.catch fails in IE11 with polyfills

I'm using ES6, Promises and fetch in my Polymer 2 project. Because I need to support at least IE11, I'm transpiling with Babel (via polymer-build) and using polyfills.io to polyfill fetch and Promise support. My polyfills.io import happens before any other imports and looks like this:

<script src="https://cdn.polyfill.io/v2/polyfill.js?features=default,fetch&flags=gated"></script>

When I load the page, this error appears in the IE11 console:

SCRIPT438: Object doesn't support property or method 'catch'

Looking through my code, the only time I'm using catch is in Promises. For example:

loadSchemas() {
  return APP.client
    .search("+type:Schema")
    .then(result => {
      // Do things with results.
    })
    .catch(error => {
      // Deal with errors.
    });
}

If I remove the catch, the page loads without errors, but then it obviously isn't running my error handling code.

Why isn't this working as expected? It works fine in Firefox, Chrome, and Safari. I tried a number of different promise polyfills and still got the same error, so I don't think it's a polyfill bug.

like image 367
ittupelo Avatar asked Aug 29 '17 17:08

ittupelo


2 Answers

So, it looks like catch is a reserved word in IE 9+. I found this nugget of information at https://github.com/lahmatiy/es6-promise-polyfill:

catch is a reserved word in IE<9, meaning promise.catch(func) throws a syntax error. To work around this, use a string to access the property:

promise['catch'](function(err) { // ... });

Or use .then instead:

promise.then(undefined, function(err) { // ... });

My code works in IE11 if I modify it to avoid catch, like so:

loadSchemas() {
  return APP.client
    .search("+type:Schema")
    .then(result => {
      // Do things with results.
    }, error => {
      // Deal with errors.
    });
}
like image 124
ittupelo Avatar answered Oct 20 '22 16:10

ittupelo


Actually, if you import /webcomponentsjs/webcomponents-lite.js polyfill (with Polymer 2.x), it will most likely rewrote the Promise polyfill. And this polyfill currently has an open issue with "catch" :

https://github.com/webcomponents/webcomponentsjs/issues/837

Where proposed Workaround is:

Pin the version of the WebComponents polyfill to 1.0.7 or less.

I took a look at the webcomponents-lite polyfill for Promise, and they replace the Promise definition if the following is false (I simplified the writing):

Object.prototype.toString.call(window.Promise.resolve()) == "[object Promise]"

However, even if you import Promise polyfill from other sources, they render to "[object Object]", hence they are replaced.

Note: the webcomponents-lite polyfill for Promise also currently doesn't expose a Promise.all() method, it's also probably due to above issue with Closure compiler.

Proposed Workaround while this issue is not fixed:

Load your polyfill after the Webcomponents polyfill.

// load webcomponents polyfills
(function() {
    if ('registerElement' in document
        && 'import' in document.createElement('link')
        && 'content' in document.createElement('template')) {
        // browser has web components
    }
    else {
        // polyfill web components
        let e = document.createElement('script');
        e.src = '/bower_components/webcomponentsjs/webcomponents-lite.js';
        document.head.appendChild(e);
    }

    // Promise polyfill for IE11, as of 2017/09/07 webcomponents Promise polyfill is broken
    // (https://github.com/webcomponents/webcomponentsjs/issues/837)
    if (!window['Promise'] || !window['Promise']['reject']){
        // Remove the webcomponents polyfilled Promise object
        delete window.Promise;

        // Add own polyfill for Promise
        let e = document.createElement('script');
        e.src = '/lib/promisePolyfill/promise.js'; // or polyfill.io
        document.head.appendChild(e);
    }
})();
like image 22
Jean-Rémi Avatar answered Oct 20 '22 16:10

Jean-Rémi