【问题标题】:Extending `Promise` and change `then` signature扩展 `Promise` 并更改 `then` 签名
【发布时间】:2018-12-22 19:38:31
【问题描述】:

我想扩展Promise 并更改then 签名,以便其回调接收两个值。我尝试了不同的方法,其中两种已记录和测试here。遗憾的是,我遇到了各种错误,或者生成的类不像 Promise。

方法一:Wrapping a native Promise

export class MyWrappedPromise {
  constructor(data) {
    this.data = data;
    this.promise = new Promise(evaluate.bind(data));
  }

  then(callback) {
    this.promise.then(() => callback(this.data, ADDITIONAL_DATA));
  }

  catch(callback) {
    this.promise.catch(callback);
  }
}

方法二:Extending native Promises

export class MyExtendedPromise extends Promise {
    
  constructor(executor, data) {
    super(executor);
    this.data = data;
  }

  static create(data) {
      return new MyExtendedPromise(evaluate.bind(data), data);
  }

  then(callback) {
    return super.then(() => callback(this.data, ADDITIONAL_DATA));
  }
}

有人对我做错了什么有任何建议吗?随意在 GitHub 上创建 PR。

谢谢

-------------------- 编辑 ---------

一些额外的代码和信息,使上面的代码更容易理解,而无需查看 Github 上的代码和测试。

evaluate 只是 Promise 执行器函数。我将其提取出来,以便在我的所有实现和测试中保持一致。它可能看起来很复杂,但它的结构是模拟我的“真实”项目。

export function evaluate(resolve, reject) {
  const data = this;
  function getPromise(data) {
    return !!data ? Promise.resolve(data) : Promise.reject(new Error("Error"));
  }

  getPromise(data)
    .then(resolve)
    .catch(reject);
}

ADDITIONAL_DATA 只是一个字符串,用于模拟回调中的第二个值。它还被提取以在所有版本和测试中保持一致。

------------------ 编辑 2---------------------强>

出现的错误取决于解决方案

  • catch 无法访问
  • 很多UnhandledPromiseRejectionWarning: 警告,因为错误/拒绝没有正确传播。
  • 错误/拒绝过早抛出,甚至没有到达我的测试套件中的 rejects 检查

【问题讨论】:

  • 改用包装器。你得到什么错误? ADDITIONAL_DATA 定义在哪里,evaluate.bind(data) 是什么?
  • 感谢您的关注。我更新了我最初的帖子,它们只是 functionString,以保持我所有实现的一致性并更好地评估我的测试用例。
  • 您遇到什么错误?你能更新你的问题吗?
  • 这背后的目标是什么?
  • 我建议不要使用extends Promise,而是从你自己的数据结构开始。将其设为thenable 以提供与承诺的兼容性

标签: javascript promise es6-promise


【解决方案1】:

您有问题(尤其是未处理的拒绝),因为您没有正确实现then 接口。请记住,.catch(onRejected) 只是.then(undefined, onRejected) 的别名,而then with two parameters 是实际的core method of every promise

你总是忽略第二个参数,所以没有处理任何拒绝。你需要写

then(onFulfilled, onRejected) {
  return super.then(res => onFulfilled(res, this.ADDITIONAL_DATA), onRejected);
  // or `this.promise.then` instead of `super.then`
}

【讨论】:

  • 谢谢,我不知道.catch只是一个别名。
【解决方案2】:

我不太明白为什么你有一个工厂方法,而不是直接使用构造函数。

你的意思是这样的吗?

class MyExtendedPromise extends Promise {

  constructor(executor, data) {
    super(executor);
    this.data = data;
  }

  then(callback, test) {
    console.log('passed new parameter in then:', test);
    console.log('additional data:', this.data);
    return super.then(data => callback(data, test));
  }
}

new MyExtendedPromise((resolve, reject) => {
	setTimeout(() => resolve(true), 2000);
}, 'other additional data').then(data => console.log('my then', data), 'hello world');

【讨论】:

  • 感谢您的浏览。我有工厂方法,因为我不想在创建承诺时传递执行器函数,而只是传递数据。 executor 函数始终相同。这种情况可能会使extended 版本成为错误的解决方案,但我尝试让生成的类尽可能接近实际的 Promise。
  • 您的意思是每次创建MyExtendedPromise的实例时,每个实例的执行器总是相同的,只是传入的数据发生变化?
  • 没错。它应该是“可链接的”和“可捕获的”。
  • 那么为什么不将自定义执行器定义为类的方法,而是直接调用该代码而不传入执行器?
  • 这就是我在真实版本中所做的,但是如果你看一下 Github,我有几个实现,我使用相同的函数进行测试,实际 Promise,这就是我提取的原因它脱离了功能。我的主要问题是,我要么无权访问catch,要么错误没有正确地向上传播,我收到大量UnhandledPromiseRejectionWarning: 警告。
猜你喜欢
  • 2016-09-06
  • 2018-05-16
  • 1970-01-01
  • 2020-02-21
  • 2017-11-02
  • 1970-01-01
  • 1970-01-01
  • 2021-04-09
  • 1970-01-01
相关资源
最近更新 更多