Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promise.prototype.finally polyfill not applying to async functions #579

Closed
vetruvet opened this issue Jun 20, 2019 · 5 comments
Closed

Promise.prototype.finally polyfill not applying to async functions #579

vetruvet opened this issue Jun 20, 2019 · 5 comments

Comments

@vetruvet
Copy link

vetruvet commented Jun 20, 2019

I spotted an issue with using native async functions with the Promise.prototype.finally polyfill. The issue comes about when using core-js in conjunction with @babel/preset-env with a browser that supports native async functions but not Promise.prototype.finally (e.g. Edge 17). It appears that the global Promise object is polyfilled but the Promise returned from an async function is not.

Repo with example to reproduce: https://github.com/vetruvet/async-finally-promise-bug
In that repo, master has a demo of the issue (open in Edge to see it fail).

Interestingly, simply setting Promise.prototype.finally to a dummy function propagates that function to the Promise returned by async functions (not-a-polyfill-demo branch in the above repo demonstrates this). Obviously the callback passed in does not get called but the intention is to demonstrate that setting finally on Promise.prototype affects the promise returned by async functions.

I am currently working around the bug in a hacky way (workaround branch in the above repo) by copying finally to the async function's Promise prototype and that seems to be working but obviously I think there should be a proper fix for this.

Also of note is that try { await ...; } catch (e) { ... } finally { ... } works just fine in Edge, just not calling .finally(...) on the return value of an async function.

@zloirock
Copy link
Owner

zloirock commented Jun 21, 2019

It's a known issue, but it's deeper than just missed .finally on async functions. It's a subset of this issue.

Edge does not pass core-js Promise feature detection, so Promise completely replaced in this engine. So, Promise.prototype.finally added to polyfilled Promise, but native async functions return a native Promise.

In corejs@3 added a workaround of this problem for fetch - a wrapper. But we can't do the same for async functions since it's syntax.

The best solution for correct work here - add a transform-wrapper to Babel for environments which do not support Promise completely, but support async functions:

async function () { /* ... */ }
// =>
function () {
  return Promise.resolve(async function () { /* ... */ }.apply(this, arguments));
}

zloirock added a commit that referenced this issue Jul 30, 2019
… `Promise`, #579

added `.finally` and patched `.then` to / on native `Promise` prototype
@zloirock
Copy link
Owner

I added a workaround which should fix a big part of cases by patching .than and adding .finally on / to native Promise prototype.

@BevanR
Copy link

BevanR commented Nov 22, 2019

We used this general function to normalize native promises returned from Stripe.js;

/**
 * Normalize promises that are not feature complete.
 *
 * @param original {Promise} Native or normalized promise.
 * @returns {Promise} Normalized feature-complete core-js promise with support for .finally().
 */
export function normalizePromise(original) {
  return new Promise((resolve, reject) => {
    original.then(resolve).catch(reject)
  })
}

E.g.

return normalizePromise(window.stripe.createToken(element, params))

@loganfsmyth
Copy link
Contributor

@BevanR That seems like a longer version of Promise.resolve(original).

@BevanR
Copy link

BevanR commented Nov 24, 2019

@loganfsmyth Indeed. Very nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants