javascript - 如何在不添加到 Promise.prototype 的情况下为 Promise 创建自定义 .andThen() 链接函数?

标签 javascript ecmascript-6 promise

我定义了一个自定义 Either 类型,并具有返回 Promise(Either(left,right)) 的函数。为了允许链接这些函数,我修改了 Promise 的原型(prototype),如下所示:

Promise.prototype.andThenE = function(andThen) {
  return this.then(p => {
    return p.fold(
      e => Promise.reject(Either.left(e)),
      s => andThen(s),
    );
  }).catch(c => c);
};

这使我能够编写如下代码:

const response = await functionXReturningPromiseEither(input).andThenE(functionYReturningPromiseEither).andThenE(...);

我知道扩展原生对象的原型(prototype)是不好的做法,我试图将这个 andThenE 拉出来并将其直接放在我的 Either 上,但我无法让它正常工作/链接。

这是我对Either的简单实现:

const Either = {};

Either.fromPromise = promise => {
  return promise.then(Either.right, Either.left);
};

Either.left = Either.failure = x => ({
  map: f => Either.left(x), //no-op: no mapping if "left" value
  fold: (l, r) => l(x), //apply "left" function to extract error value
  andThen: f => Either.left(x), //or flatMap or chain or join: Left(Left(x)) -> Left(x)
  dump: () => x, //for debugging
});

Either.right = Either.success = x => ({
  map: f => Either.right(f(x)), //map only if "right"
  fold: (l, r) => r(x), //apply "right" function to extract success value
  andThen: f => f(x), //or flatMap or chain or join: Right(Right(x)) -> Right(x)
  dump: () => x, //for debugging
});

如果我这样做,它会完美地工作:

const f = async (arr) => Either.right(arr.map(x => x+1));

const res = await Either.fromPromise(Promise.resolve([1])).andThenE(f).andThenE(f);
console.log(res.dump());    //[3] - is of type Either.right([3])

但是,我无法以任何有意义的方式让 andThenE 成为 Either 的成员。

我尝试这样做但没有成功:

PromiseEither = promise => ({
  andThenE: f => {
    return PromiseEither(promise.then(p => {
      console.log("inside promise");
      return p.fold(
        e => Promise.reject(Either.left(e)),
        s => s.andThen(f),
      );
    }).catch(c => c));
  },
});

Either.fromPromise = promise => {
 PromiseEither(promise.then(Either.right, Either.left))
}

这没有成功:

const res = await Either.fromPromise(Promise.resolve([1])).andThenE(f).andThenE(f);
console.log(res); //prints PromiseEither's structure and await is meaningless

我尝试了许多其他变体来了解其效果。我认为这很简单,但经过几个小时的努力,我没有取得任何进展。我可能缺少什么?这可能吗?

Link to fiddle

最佳答案

首先,我想强调我不会这样做。我认为这不是一个好主意,因为 Promise 已经有一个错误处理模型,这就是我使用 Either 时通常使用的模型。

如果您愿意,我会从头开始 - 并使用 .then 作为您的类型(具有不同错误处理的延续)和 promise 之间的互操作点。

这就是说,做你想做的事情的标准方法是使用子类化(恶心)或Symbol.species(甚至更恶心)。我将展示第一个选项,并将第二个选项留给热心读者作为练习:

class PromiseEither extends Promise {
  andThenE(f) {
    return PromiseEither(this.then(p => {
      console.log("inside promise");
      return p.fold(
        e => Promise.reject(Either.left(e)),
        s => s.andThen(f),
      );
    }).catch(c => c)); // I would not do this .catch if I were you btw
  }
});

}

我会警告不要使用 Promise 子类化 - 这是非常棘手的。在我看来,甚至从新领域获取 Promise 副本并改变原型(prototype)(如 Node 中的 iframe 或 vm)也是更好的选择。

关于javascript - 如何在不添加到 Promise.prototype 的情况下为 Promise 创建自定义 .andThen() 链接函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64021563/

相关文章:

javascript - 带两个参数的回调 ES6 箭头函数 Angular2

javascript - 这个错误是什么意思——Uncaught TypeError : Already read?

javascript - 在javascript中的一系列函数之后返回

javascript - 除了某些单词外,每个单词的第一个单词都要大写

Javascript:按三个值对对象数组进行排序

javascript - 具有不同 json 变量的循环显示所有项目而不是每个项目一个

javascript - $.getScript 不工作 (IE8)

javascript - 如何过滤对象数组内的数组

javascript - 什么时候使用 jQuery 动画 promise 而不是回调?

javascript - 如何从 javascript 中包含 2 个或更多项目的值获取数据