【问题标题】:Receive message from an Elm process从 Elm 进程接收消息
【发布时间】:2021-08-13 04:35:02
【问题描述】:

我正在玩弄 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

【问题讨论】:

    标签: process ipc elm


    【解决方案1】:

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

    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 流程。

    【讨论】:

      【解决方案2】:

      Elm 进程目前还不是完全成熟的 API。单独使用 Process 库无法完成您想做的事情。

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

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

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

      目前,这个库非常稀少。例如,没有供进程相互通信的公共 API。

      【讨论】:

      • 因此,(a) Process 无法接收消息,并且 (b) 一个 Process 无法与另一个 Process 交谈。但这是否意味着生成的Process 无法向“主应用程序”发送消息。也许确实如此,但我不明白如何
      • 我认为目前的 API 没有办法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-08
      相关资源
      最近更新 更多