我定义了一个自定义 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
我尝试了许多其他变体来了解其效果。我认为这很简单,但经过几个小时的努力,我没有取得任何进展。我可能缺少什么?这可能吗?
最佳答案
首先,我想强调我不会这样做。我认为这不是一个好主意,因为 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/