如何在Elm中实现setTimeout的行为

Tom*_*ski 22 elm

我正在Elm写一个带有很多时间依赖事件的网页游戏,我正在寻找一种方法来安排特定时间延迟的事件.

在我使用的JavaScript中setTimeout(f, timeout),显然效果非常好,但是 - 出于各种原因 - 我想避免使用JavaScript代码并单独使用Elm.

我知道我可以subscribeTick特定间隔收到时钟滴答,但这不是我想要的 - 我的延迟没有合理的共同点(例如,两个延迟是30ms和500ms),我想避免必须处理许多不必要的滴答声.

我也遇到了TaskProcess-似乎通过他们我莫名其妙地能什么我想Task.perform failHandler successHandler (Process.sleep Time.second).

这可行,但不是很直观 - 我的处理程序只是忽略所有可能的输入并发送相同的消息.此外,我不希望超时失败,因此创建失败处理程序感觉就像是在为图书馆供电,这不是我对这种优雅语言所期望的.

是否存在类似于Task.delayMessage time message我需要的东西(在指定时间后发送给我的消息参数的副本),或者我是否必须为它创建自己的包装器?

小智 30

@ wintvelt的答案的更新和简化版现在是:

delay : Time.Time -> msg -> Cmd msg
delay time msg =
  Process.sleep time
  |> Task.perform (\_ -> msg)
Run Code Online (Sandbox Code Playgroud)

具有相同的用法

  • [Process.sleep](https://package.elm-lang.org/packages/elm/core/latest/Process#sleep)以“浮点数”作为第一个参数。 (2认同)

win*_*elt 25

如果你想要"每x秒"发生一次事情,那么像@ChadGilbert所描述的那样的订阅就像你需要的那样.(或多或少像javascript一样setInterval().

另一方面,如果你想要的事情只发生在"一次,在x秒之后",那么Process.sleep路线就是要走的路.这相当于javascript setTimeOut():经过一段时间后,它会做一次.

您可能必须为它制作自己的包装器.就像是

-- for Elm 0.18
delay : Time -> msg -> Cmd msg
delay time msg =
  Process.sleep time
  |> Task.andThen (always <| Task.succeed msg)
  |> Task.perform identity
Run Code Online (Sandbox Code Playgroud)

像这样使用:

---
update msg model =
  case msg of
    NewStuff somethingNew ->
      ...

    Defer somethingNew ->
      model
      ! [ delay (Time.second * 5) <| NewStuff somethingNew ]
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法在超时到期之前取消延迟操作? (6认同)
  • "取消"的一种方法是在模型中设置一个标志,然后在最终消息的情况下检查该标志(在上面的例子中为"NewStuff") (3认同)

Cha*_*ert 23

最初可能不明显的一件事是订阅可以根据模型进行更改.每次更新后都会对其进行有效评估.您可以使用此事实以及模型中的某些字段来随时控制哪些订阅处于活动状态.

这是一个允许变量光标闪烁间隔的示例:

subscriptions : Model -> Sub Msg
subscriptions model =
    if model.showCursor
        then Time.every model.cursorBlinkInterval (always ToggleCursor)
        else Sub.none
Run Code Online (Sandbox Code Playgroud)

如果我理解您的担忧,这应该克服处理不必要的滴答的可能性.您可以使用多个不同间隔的订阅Sub.batch.


iEl*_*ric 6

榆树 v0.19

执行一次并延迟:

delay : Float -> msg -> Cmd msg
delay time msg =
    -- create a task that sleeps for `time`
    Process.sleep time
        |> -- once the sleep is over, ignore its output (using `always`)
           -- and then we create a new task that simply returns a success, and the msg
           Task.andThen (always <| Task.succeed msg)
        |> -- finally, we ask Elm to perform the Task, which
           -- takes the result of the above task and
           -- returns it to our update function
           Task.perform identity
Run Code Online (Sandbox Code Playgroud)

要执行重复任务:

every : Float -> (Posix -> msg) -> Sub msg
Run Code Online (Sandbox Code Playgroud)