【发布时间】:2020-09-23 20:45:14
【问题描述】:
我想以有原则的方式将命令式 Promise 转换为函数式 Task:
const record = (type, o) =>
(o[type.name || type] = type.name || type, o);
const thisify = f => f({});
const taskFromPromise = p =>
Task((res, rej) =>
p.then(res)
.catch(x => rej(`Error: ${x}`)));
const Task = task => record(
Task,
thisify(o => {
o.task = (res, rej) =>
task(x => {
o.task = k => k(x);
return res(x);
}, rej);
return o;
}));
const tx = taskFromPromise(Promise.resolve(123)),
ty = taskFromPromise(Promise.reject("reason").catch(x => x));
// ^^^^^ necessary to avoid uncaught error
tx.task(console.log); // 123
ty.task(console.log); // "reason" but should be "Error: reason"
解决方案有效,但拒绝无效,因为Promises 被急切地触发。如果我放弃了catch 处理程序,我将不得不将整个计算放入try/catch 语句中。有没有更可行的选择?
【问题讨论】:
-
您的
task方法需要两个参数,但您只传递了一个参数。 -
我看不出你的
Task比承诺“更不重要”或“更实用”。如果您可以在它们之间来回转换,那么它们在大多数情况下都是相等的。预期的区别是什么? -
Promise立即调用传递的函数,而Task创建一种函数组合形式。两者都是根本不同的操作,我不会列出后果,因为您肯定知道它们。也许你认为Task是必要的,因为它会导致本地突变以启用共享。我还不确定多播是否是有害的或可取的属性。答案可能取决于您是否需要取消。 -
是的,您的
Task只是一个Promise具有延迟初始执行,而不是一个函数。正是这种突变和异步效果的结果共享breaks the monad properties for promises 使它们成为必不可少的工具。 (你的分享也被破坏了,因为它不会在承诺完成之前发生,也不会考虑拒绝)。 -
运行
Task是 Javascript 的运行时。运行时没有 RT,因为所有效果都被释放。不分享拒绝案例是一个设计决策。 你的分享也被破坏了,因为它不会在承诺实现之前发生 - 这是一个有偏见的陈述。Tasks 不是承诺。共享仅适用于有限的用例。
标签: javascript asynchronous ecmascript-6 functional-programming