从 Elm 进程接收消息

问题描述

我正在玩弄 Elm processes 以了解有关它们如何工作的更多信息。在这部分内容中,我正在尝试实现一个计时器。

然而,我遇到了一个障碍:我无法在其余代码中找到访问流程任务结果的方法

有那么一瞬间,我希望如果我使用 Cmd解决任务,Elm 运行时会很好地为我执行这种效果,但这是一个天真的想法:

type Msg
  = Spawned Process.Id
  | TimeIsUp

init _ =
  ( nothing,Task.perform Spawned (Process.spawn backgroundTask)
  )

backgroundTask : Task.Task y (Platform.Cmd.Cmd Msg)
backgroundTask =
  Process.sleep 1000
    -- pathetic attempt to send a Msg starts here
    |> Task.map ( always
                  <| Task.perform (always TimeIsUp)
                  <| Task.succeed ()
                )
    -- and ends here
    |> Task.map (Debug.log "Timer finished") -- logs "Timer finished: <internals>"

update msg state =
  case msg of
    Spawned id ->
      (Just id,Cmd.none)

    TimeIsUp ->
      (nothing,Cmd.none)

view state =
  case state of
    Just id ->
      text "Running"

    nothing ->
      text "Time is up"

docs

没有用于进程相互通信的公共 API。

我不确定这是否意味着进程无法与应用的其余部分进行通信。

有没有办法让 update 函数在进程退出后收到 TimeIsUp

解决方法

有一种方法,但它需要一个地狱端口:

  1. 从进程中发出一个虚假的 HTTP 请求,
  2. 然后通过 JavaScript 拦截它
  3. 并将其传回给 Elm。
port ofHell : (() -> msg) -> Sub msg

subscriptions _ =
  ofHell (always TimeIsUp)

backgroundTask : Task.Task y (Http.Response String)
backgroundTask =
  Process.sleep 1000
    -- nasty hack starts here 
    |> Task.andThen ( always
                      <| Http.task { method = "EVIL",headers = [],url = "",body = Http.emptyBody,resolver = Http.stringResolver (always Ok ""),timeout = Nothing 
                                   }
                    )

在幕后,Http.task 调用 new XMLHttpRequest(),因此我们可以通过重新定义该构造函数来拦截它。

<script src="elm-app.js"></script>
<div id=hack></div>
<script>
  var app = Elm.Hack.init({
    node: document.getElementById('hack')
  })

  var orig = window.XMLHttpRequest
  window.XMLHttpRequest = function () {
    var req = new orig()
    var orig = req.open
    req.open = function (method) {
      if (method == 'EVIL') {
        app.ports.ofHell.send(null)
      }
      return orig.open.apply(this,arguments)
    }
    return req
  }
</script>

该解决方案尚未准备好投入生产,但它确实让您可以继续使用 Elm 流程。

,

Elm Processes 目前还不是一个成熟的 API。单独使用 Process 库是不可能做到的。

请参阅文档中关于 Process.spawn 的注释:

注意:这会创建一种相对受限的进程,因为它无法接收任何消息。后续版本将提供更多的用户定义流程灵活性!

以及整个 Future Plans 部分,例如:

现在,这个库非常稀少。例如,没有用于进程相互通信的公共 API。