请考虑一个在浏览器中运行的 scala.js 应用程序,它由一个主程序和一个 Web Worker 组成。
主线程通过传递包含方法名称和调用它们所需的参数的消息,将长时间运行的操作委托(delegate)给 Web Worker。 Worker 将方法返回值以响应消息的形式传递回主线程。
简单来说,该程序抽象了 Web 工作线程消息传递,以便主线程中的代码可以使用惯用的异步 Scala 语法调用工作线程中的方法。
因为 Web Worker 不会以任何方式将消息与其响应关联起来,所以抽象依赖于注册表(一个中间对象),它控制每个跨上下文方法调用以将调用与结果关联起来。这个单例也可以绑定(bind)回调函数,但是有没有办法用 future 而不是回调来实现这一点?
如何在此注册表上构建抽象,以允许程序员将其与 Scala 中的标准异步编程结构一起使用: future 和 promise ?
我应该如何编写这个功能,以便 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) }
我对 futures 和 Promise 很陌生,但似乎它们通常在某些执行 block 终止时完成。在这种情况下,收到网络 worker 的响应就意味着 future 的完成。有没有办法编写一个自定义 future ,将其完成状态委托(delegate)给外部流程?是否有另一种方法可以将 Web Worker 响应消息链接到 future 的状态?
我可以/应该扩展 Future 特征吗?这在 Scala.js 中可能吗?我应该扩展一个具体的类(class)吗?是否有其他方法可以将这些跨上下文 Web Worker 方法调用封装到现有的异步 Scala 功能中?
感谢您的考虑。
最佳答案
嗯。只是在这里吐槽一下(我还没有使用过 worker ),但在您正在工作的单线程 JavaScript 世界中,将请求与 Future 关联起来似乎相当容易。
这是一个假设的设计。假设对工作人员的每个请求/响应都自动包装在一个信封中;信封包含一个 RequestId。所以发送端看起来像这样(这是伪代码,但是真实的):
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 一样简单......
关于multithreading - 如何在 future 中包装 Web Worker 响应消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44348491/