与Scala等函数式语言相比,Js延迟/承诺/未来

时间:2014-03-28 23:24:28

标签: javascript scala promise future deferred

我主要使用Scala和JavaScript等编程语言。我试图理解在两种语言中如何使用异步响应式编程的相似点和不同点。你能救我吗?

我没有采用任何特定的Js Promise框架,因为它似乎很多都实现了类似的规范(如Promise / A)。到目前为止我只使用过Q.


似乎在Javascript中我们调用Deferred我们解决的对象来完成Promise。 在Scala中,似乎Promise是你决定获得Future monad的对象。

有人可以告诉我这是否正确?是否有充分的理由在Js和Scala之间使用术语Promise


此外,在Scala中,我们通常使用Futuremap(在Haskell中也称为flatMap)等运算符对bind monad进行进一步计算。在Js中这些相当于什么?

我可能错了,但在我看来,then Promise map处理flatMappromise of promise of result运算符对吗?如果是这样,是否有可能在Js中获得Future[Future[Result]]?就像我们可以在Scala中获得Future[Result](无论如何都可以将其展平为Promise。)


Js {{1}}是monad吗?即使方法名称与我们在monad文献中找到的名称不匹配,它似乎也是如此。

4 个答案:

答案 0 :(得分:36)

是的,没有。

虽然非常相似。使用符合Promises / A +规范.then的JavaScript Promise并不是真正的monadic绑定,而且.map.flatMap都是.thenPromise.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"); }); 。返回一个承诺时,在.chain处理程序内,它会以递归方式展开它。

Future[Future

(fiddle)

你是正确的,标准的JS承诺库和A +规范没有monadic承诺。已经讨论过它们,并且存在fantasy-promises之类的实现。他们遵循不同的规范,几乎没有采用。另请参阅this。在语言设计讨论论坛上一直在讨论这个问题 - esdescuss和monadic .then方法没有平面图并允许monadic promises被考虑但不太可能成功。

这是出于务实的原因。实施当前的承诺方式非常有用。很少见到您实际需要Promise[Promise[Value]]的情况,通常您希望继续使用该语言。承诺从单子“借”,从某种意义上来说就是“monadic”。 Future[Future[Value]] 非常接近绑定,在我脑海中,我可以互换使用它们。

在Scala中使用大多数承诺库都不可能像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 }); 。你必须将它包装在一个对象中并拥有{{1}}。

{{1}}

(fiddle)

两者之间还存在许多其他较小的差异,但通常你的断言是正确的。

答案 1 :(得分:1)

  

似乎在Javascript中我们称之为Deferred我们解决的对象>完成Promise。在Scala中,似乎Promise是你为解决未来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 + specs中,它们捆绑在一起,Promise.then用于链接和检索副作用的值(例如console.log),写入你将使用resolve之类的下面的代码段

var promise = new Promise(function(resolve, reject){
    Thread.sleep(10000);
    resolve("promise completed");
}

答案 2 :(得分:0)

  

我试图理解在两种语言中如何使用异步反应式编程的相同点和不同点。

此文档不会将Javascript承诺与Scala进行比较,而是使用C ++ C#和Python进行Javascript承诺:https://github.com/KjellSchubert/promise-future-task。我知道那不完全是你所要求的,但这可能会给你一些有趣的指示。

答案 3 :(得分:0)

与Scala相比, the JS Promise is not a monad, due to the implicit "thenable" unwrapping breaking monadic law。 但是,您可以实现基于回调的monadic语义和功能,以达到相同的目的。

例如参见the cpsfy library

此外,由于.then接受2个功能,而.chain仅接受一个功能,因此存在结构差异。但是,可以实现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
)