2017-06-03 27 views
1

请考虑运行在浏览器中的一个scala.js应用程序,它由一个主程序和一个web worker组成。如何在期货中包装Web Worker响应消息?

主线程通过传递包含方法名称和调用它们所需参数的消息,将长时间运行的操作委托给Web Worker。工作人员以响应消息的形式将方法返回值传递回主线程。

简单来说,这个程序会抽象出web worker的消息传递,这样主线程中的代码就可以在工作线程中以惯用和异步的Scala语法调用方法。

因为网络工作人员不会以任何方式将消息与其响应关联起来,所以抽象依赖于注册中心,一个中介对象,该中介对象控制每个跨上下文方法调用以将调用与结果相关联。这个单例还可以绑定回调函数,但是有没有一种方法可以通过期货而不是回调来实现?

如何在此注册表上构建一个抽象,允许程序员将它与Scala中的标准异步编程结构一起使用:期货和承诺?

我应该如何编写这个功能,以便scala程序员能够以规范的方式与它交互?例如:

// long running method in the web worker 
val f: Future[String] = Registry.ultimateQuestion(42) // async 

f onSuccess { case q => println("The ultimate question is: " + q) } 

我不熟悉期货和承诺,但看起来他们通常在某些执行块终止时完成。在这种情况下,收到网络工作者的回应意味着未来的完成。有没有办法编写一个将其完成状态委托给外部过程的自定义未来?是否有另一种方式将网络工作者的回应信息与未来的状态联系起来?

可以/我应该延长未来的特质吗?这可能在Scala.js中吗?我应该延伸一个具体的课程吗?有没有其他的方式来封装这些跨现有的Web工作方法调用现有的异步Scala功能?

谢谢您的考虑。

回答

2

嗯。只是在这里吐了口水(我还没有使用过工人),但似乎将请求与Future相关联在您正在使用的单线程JavaScript世界中相当容易。

这是一个假设设计。假设对工作人员的每个请求/响应都自动包装在信封中;信封包含一个RequestId。因此,发送端看起来像(这是伪代码,但实际ISH):

def sendRequest[R](msg:Message):Future[R] = { 
    val promise = Promise[R] 
    val id = nextRequestId() 
    val envelope = Envelope(id, msg) 
    register(id, promise) 
    sendToWorker(envelope) 
    promise.future 
} 

工作进程味精,包装在另一个信封结果,结果被处理回主线程与是这样的:

def handleResult(resultEnv:Envelope):Unit = { 
    val promise = findRegistered(resultEnv.id) 
    val result = resultEnv.msg 
    promise.success(result) 
} 

这需要一些填充,以及有关类型,如R应该是什么样的一些想法,但那种轮廓可能会工作体面的好。如果这是JVM,你不得不担心各种竞争条件,但在单线程的JS世界中,它可能就像为请求ID使用自动递增整数一样简单,并存储Promise ...

+0

哦!所以Promise允许程序员通过调用一个setter来确定何时履行承诺?如果这样做,我应该重新命名这个问题:“我不知道什么是承诺!”谢谢,贾斯汀!:) –

+0

正确。承诺和期货基本上是一脉相承的 - 你可以将承诺视为“生产者”一方,将未来视为“消费者”一方。上面说明的模式 - 创建Promise,返回promise.future,当事情真的完成时,调用promise.success()的值 - 几乎是将“callback-y”API连接到线程的标准方式期货。 –