如何在Edge中添加polyfill以支持finally()?

时间:2018-11-15 20:50:38

标签: javascript promise polyfills finally

我正在使用axios库,并使用then(),catch()和finally()。在Chrome中完美运行。但是,finally()方法在MS Edge中不起作用。我使用填充胶或垫片进行了研究,但我迷路了。我不使用webpack或转译,也不打算添加它们。我需要保持简单。如何添加polyfill以确保finally()在Edge中工作?谢谢!

1 个答案:

答案 0 :(得分:8)

这实际上比我想象的要难。除以下详述的行为外,这甚至还应处理随后的species的传播:

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

此实现基于finally()的已记录行为,并且取决于then()是否符合规范:

  
      
  • finally回调将不会接收任何参数,因为没有可靠的方法来确定诺言是否已兑现。正是这种用例适用于您不关心拒绝原因或实现价值,因此不需要提供它的情况。

  •   
  • Promise.resolve(2).then(() => {}, () => {})(将由undefined解决)不同,Promise.resolve(2).finally(() => {})将由2解决。

  •   
  • 类似地,与Promise.reject(3).then(() => {}, () => {})(将由undefined实现)不同,Promise.reject(3).finally(() => {})将被3拒绝。

  •   
     

注意:throw回调中的finally(或返回被拒绝的承诺)将以调用throw()时指定的拒绝原因来拒绝新的承诺。

当然还有等效行为的演示:

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));

test('native');

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

test('polyfill');

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

  delay(2, 1000)
    .finally(first('settled'))
    .then(first('fulfilled'), first('rejected'));

  const second = log('second');

  delay(Promise.reject(3), 2000)
    .finally(second('settled'))
    .then(second('fulfilled'), second('rejected'));

  const third = log('third');

  delay(4, 3000)
    .finally(third('settled'))
    .finally(() => delay(6, 500))
    .then(third('fulfilled'), third('rejected'));

  const fourth = log('fourth');

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

感谢@Bergi在此答案上的投入。如果您认为这篇文章有帮助,请参阅his implementation并对其进行投票。