How to add a polyfill to support finally() in Edge?

余生长醉 提交于 2019-12-29 01:34:29

问题


I'm using axios library and using then(), catch() and finally(). Works perfectly in Chrome. However the finally() method does not work in MS Edge. I researched using polyfills or shims and I'm lost. I am not using webpack or transpiling and don't plan to add them. I need to keep this simple. How can I add a polyfill to make sure finally() works in Edge? Thanks!


回答1:


This should handle the propagation of the thenable's species in addition to the behaviors detailed below:

Promise.prototype.finally = Promise.prototype.finally || {
  finally (fn) {
    const onFinally = value => Promise.resolve(fn()).then(() => value);
    return this.then(
      result => onFinally(result),
      reason => onFinally(Promise.reject(reason))
    );
  }
}.finally;

This implementation is based on the documented behavior of finally() and depends on then() being compliant to the specification:

  • A finally callback will not receive any argument, since there's no reliable means of determining if the promise was fulfilled or rejected. This use case is for precisely when you do not care about the rejection reason, or the fulfillment value, and so there's no need to provide it.

  • Unlike Promise.resolve(2).then(() => {}, () => {}) (which will be resolved with undefined), Promise.resolve(2).finally(() => {}) will be resolved with 2.

  • Similarly, unlike Promise.reject(3).then(() => {}, () => {}) (which will be fulfilled with undefined), Promise.reject(3).finally(() => {}) will be rejected with 3.

Note: A throw (or returning a rejected promise) in the finally callback will reject the new promise with the rejection reason specified when calling throw().

And of course a demonstration of equivalent behavior:

const logger = (label, start = Date.now()) => (...values) => {
  console.log(label, ...values, `after ${Date.now() - start}ms`);
};

const delay = (value, ms) => new Promise(resolve => {
  setTimeout(resolve, ms, value);
});

// run test on native implementation
test('native');

// force Promise to use the polyfill implementation
Promise.prototype.finally = /* Promise.prototype.finally || */ {
  finally (fn) {
    const onFinally = value => Promise.resolve(fn()).then(() => value);
    return this.then(
      result => onFinally(result),
      reason => onFinally(Promise.reject(reason))
    );
  }
}.finally;

// run test on polyfill implementation
test('polyfill');

function test (impl) {
  const log = ordinal => state => logger(`${ordinal} ${impl} ${state}`);
  const first = log('first');

  // test propagation of resolved value
  delay(2, 1000)
    .finally(first('settled'))
    .then(first('fulfilled'), first('rejected'));

  const second = log('second');

  // test propagation of rejected value
  delay(Promise.reject(3), 2000)
    .finally(second('settled'))
    .then(second('fulfilled'), second('rejected'));

  const third = log('third');

  // test adoption of resolved promise
  delay(4, 3000)
    .finally(third('settled'))
    .finally(() => delay(6, 500))
    .then(third('fulfilled'), third('rejected'));

  const fourth = log('fourth');

  // test adoption of rejected promise
  delay(5, 4000)
    .finally(fourth('settled'))
    .finally(() => delay(Promise.reject(7), 500))
    .then(fourth('fulfilled'), fourth('rejected'));
}
.as-console-wrapper{max-height:100%!important}

Thanks to @Bergi for his input on this answer. Please see his implementation and upvote it as well if you found this post helpful.



来源:https://stackoverflow.com/questions/53327711/how-to-add-a-polyfill-to-support-finally-in-edge

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!