如何在Elm中实现setTimeout的行为

时间:2016-11-14 23:22:29

标签: elm

我正在Elm写一个带有很多时间相关事件的网络游戏,我正在寻找一种方法来安排特定时间延迟的活动。

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

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

我也遇到了TaskProcess - 似乎通过使用它们,我可以通过Task.perform failHandler successHandler (Process.sleep Time.second)以某种方式满足我的需求。

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

是否有类似Task.delayMessage time message的东西可以完全满足我的需要(在指定的时间后发给我一个消息参数的副本),或者我是否必须为它制作自己的包装器?

4 个答案:

答案 0 :(得分:28)

现在更新简化版@wintvelt's answer

_.filter

具有相同的用法

答案 1 :(得分:23)

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

以下是允许variable cursor blink interval

的示例
subscriptions : Model -> Sub Msg
subscriptions model =
    if model.showCursor
        then Time.every model.cursorBlinkInterval (always ToggleCursor)
        else Sub.none

如果我理解您的担忧,这应该克服处理不必要的滴答声的可能性。您可以使用Sub.batch

进行多次不同时间间隔的订阅

答案 2 :(得分:23)

如果你想要“每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

使用例如像这样:

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

    Defer somethingNew ->
      model
      ! [ delay (Time.second * 5) <| NewStuff somethingNew ]

答案 3 :(得分:2)

榆木0.19:

要执行一次并延迟:

delay : Float -> msg -> Cmd msg
delay time msg =
  Process.sleep time
  |> Task.andThen (always <| Task.succeed msg)
  |> Task.perform identity

要执行重复任务:

every : Float -> (Posix -> msg) -> Sub msg