Js Deferred/Promise/Future 与 Scala 等函数式语言相比
Posted
技术标签:
【中文标题】Js Deferred/Promise/Future 与 Scala 等函数式语言相比【英文标题】:Js Deferred/Promise/Future compared to functional languages like Scala 【发布时间】:2014-05-08 15:01:51 【问题描述】:我主要使用 Scala 和 javascript 等编程语言。我试图了解异步反应式编程在两种语言中的使用方式的异同。你能帮帮我吗?
我没有采用任何特定的 Js Promise
框架,因为它似乎很多实现了类似的规范(如 Promise/A)。到目前为止我只用过Q。
似乎在 Javascript 中,我们调用了 Deferred
,我们解析为完成 Promise
的对象。
在 Scala 中,Promise
似乎是您解析以获得 Future
monad 的对象。
谁能告诉我这是否正确?在 Js 和 Scala 之间,Promise
一词的不同用法有什么好的理由吗?
此外,在 Scala 中,我们通常使用 map
和 flatMap
等运算符(在 Haskell 中也称为 bind
)将 Future
monad 与进一步的计算联系起来。 Js中的这些等价物是什么?
我可能错了,但在我看来,在 Js 中 Promise
上的 then
处理 map
和 flatMap
运算符对吗?如果是这样,是否有可能在Js中获得promise of promise of result
?就像我们可以在 Scala 中获得 Future[Future[Result]]
一样(无论如何都可以将其展平为 Future[Result]
)。
Js Promise
是单子吗?即使方法名称与我们在 monad 文献中找到的名称不匹配,它似乎也是如此。
【问题讨论】:
【参考方案1】:是的,也不是。
虽然极其相似。对于符合 Promises/A+ 规范的 JavaScript Promises,.then
并不是真正的单子绑定,.map
和 .flatMap
两者都执行。在 .then
处理程序中,当您返回一个 Promise 时,它将递归地解包它。
Promise.delay(1000).then(function()
return Promise.delay(1000).then(function ()
return Promise.delay(2000);
).then(function ()
return Promise.delay(5000)
);
).then(function ()
alert("This is only shown after 8 seconds and not one");
);
(fiddle)
您是正确的,标准 JS 承诺库和 A+ 规范不具有单子承诺。它们已经被讨论过,并且存在像 fantasy-promises 这样的实现。他们遵循不同的规范并且很少采用。另见this。在语言设计讨论论坛中一直在讨论它 - esdiscuss 和一个不平面映射并允许 monadic promises 的 monadic .chain
方法被考虑但不太可能实现。
这是出于务实的原因。当前实现承诺的方式非常有用。很少有你真正想要Future[Future
的情况,通常你希望延续只在该语言中工作。 Promise 从 monad 中“借用”,并且在某种意义上本身就是“monadic”。 .then
非常接近绑定,在我的脑海中我可以互换使用它们:)
对于大多数 Promise 库,在 Scala 中不可能有像 Future[Future[Value]]
这样的 Promise[Promise[Value]]
。您必须将其包装在一个对象中并拥有Promise[Container[Promise[Value]]]
。
Promise.delay(1000).then(function ()
return Promise.delay(1000).then(function ()
return
wrap: Promise.delay(2000).then(function ()
return Promise.delay(5000);
)
;
);
).then(function ()
alert("This logs after 1 second");
// I've also not seen a really solid use case
// except TypeScript type inference which is meh
);
(fiddle)
两者之间还有许多其他较小的差异,但通常您的断言是正确的。
【讨论】:
谢谢。对不起,我忘了接受你的好回答。我猜 JS 选择了务实的道路,主要是因为它是一种动态类型的语言,不像 Scala Benjamin,好的,但为什么是 8 秒和 1 秒?当然是 9 秒和 2 秒。更新了小提琴 - 1,2。【参考方案2】:似乎在 Javascript 中,我们将解析的对象称为 Deferred >完成 Promise。在 Scala 中,Promise 似乎是您>解决以获得 Future monad 的对象。
谁能告诉我这是否正确? >Js 和 Scala 对 Promise 一词的不同用法有什么好的理由吗?
在 Scala 中,Promise 和 Future 具有分离的功能,Future 是一个异步计算容器,它会在将来返回一些值,Promise 是异步计算的编写部分,您可以执行以下操作
val promise = Promise[String]
val future1 = promise.future
val future2 = future1.map case s => println(s); s
future2.onSuccess case s => println(s + " 2nd time")
promise.success("promise completed")
执行最后一条语句后,输出将是
promise completed
promise completed 2nd time
在 Scala 中,您可以使用 onComplete 从 Future 读取值,或者使用 map 将其链接起来,然后使用 Promise 对应物写入 Future
在 JS Promise A+ 规范中,它们被捆绑在一起,Promise.then
用于链接和检索副作用的值(例如 console.log),写你将使用 resolve
就像代码 sn-p下面
var promise = new Promise(function(resolve, reject)
Thread.sleep(10000);
resolve("promise completed");
【讨论】:
【参考方案3】:我试图了解异步响应式编程在两种语言中的使用方式的异同。
这里的文档没有将 Javascript Promise 与 Scala 进行比较,而是将 Javascript Promise 与 C++ C# 和 Python 进行比较:https://github.com/KjellSchubert/promise-future-task。我知道这并不完全是您所要求的,但这可能会给您一些有趣的建议。
【讨论】:
【参考方案4】:与 Scala 相比, the JS Promise is not a monad, due to the implicit "thenable" unwrapping breaking monadic law。 但是,您可以实现基于回调的一元语义和功能,以达到相同的目的。
参见例如the cpsfy
library.
另外,由于.then
接受2 个函数,而.chain
只接受1 个函数,存在结构上的差异。但是,可以实现一个chain
接受 2 甚至任意数量的参数函数,例如和
CPS
wrapper from cpsfy
:
//function returning CPS function with 2 callbacks
const readFileCps = file => (onRes, onErr) =>
require('fs').readFile(file, (err, content) =>
err ? onErr(err) : onRes(content)
)
// CPS wraps a CPS function to provide the API methods
const getLines = CPS(readFileCps('name.txt'))
// map applies function to the file content
.map(file => file.trim())
.filter(file => file.length > 0)
// chain applies function that returns CPS function
.chain(file => readFileCps(file))
.map(text => text.split('\n'))
// => CPS function with 2 callbacks
// To use, simply pass callbacks in the same order
getLines(
lines => console.log(lines), // onRes callback
err => console.error(err) // onErr callback
)
【讨论】:
以上是关于Js Deferred/Promise/Future 与 Scala 等函数式语言相比的主要内容,如果未能解决你的问题,请参考以下文章