如何使用Babel和ES6正确地继承Promises

时间:2017-10-14 08:21:07

标签: javascript ecmascript-6 promise babeljs es6-promise

通常使用ES6类,复合类很容易,比如

class A extends B { /*...*/ }

当谈到像Promises这样的原生内置类时,虽然很多文章都建议避免使用子类化。巴贝尔本身显然无法转变such use cases。是否有可能正确地转换子类或甚至调整下面的例子?

PS我正在使用汇总ES2015 preset,并尝试将transform-builtin-classes.babelrc

一起管道
class P extends Promise {
  foo(func) {
    return this.then(func)
  }
  static bar(a) {
    return a
  }
}

1 个答案:

答案 0 :(得分:1)

ES5中内置类继承存在障碍,有时可以通过使用Reflect.constructObject.setPrototypeOf的组合作为解决方法来避免。这是Babel transform-builtin-classes使用的方法。

此方法适用的事实取决于内置类的工作原理。如果是Promise,则可能需要从内置继承的其他中间类,然后可以使用常规class ... extends继承它。

function _P(executor) {
  return Reflect.construct(Promise, [executor], P);
}

Object.setPrototypeOf(_P, Promise);
_P.prototype = Object.create(Promise.prototype);

class P extends _P {
  static bar(arg) {
    return new this(resolve => resolve(arg));
  }

  foo(...fns) {
    return this.then(...fns);
  }
}

这确定了correct prototype chain。这种方法的缺点是它被硬编码为P子类,难以进一步扩展。

更简洁的方法是使中间类包装内置类实例。这需要在中间类中复制原始类API,但由于它很小,这对原型链来说是可接受的权衡,没有任何限制:

function _P(executor) {
  this._promise = new Promise(executor);
}

Object.setPrototypeOf(_P, Promise);
_P.prototype = Object.assign(
  Object.create(Promise.prototype),
  {
    then(...args) {
      return this._promise.then(...args);
    },
    ...
  }
);

class P extends _P { ... }

应该注意,此功能已经通过promise ponyfills提供,包括mapSeries。将它们作为自包含辅助函数使用通常是P子类的首选替代方法,考虑到每个本机承诺都应转换为P承诺P.resolve,以便从其他功能中受益。