如何在 Elm 中实现 setTimeout 的行为
How to achieve behavior of setTimeout in Elm
我正在用 Elm 编写一个包含大量时间相关事件的网络游戏,我正在寻找一种在特定时间延迟安排事件的方法。
在 JavaScript 中我使用了 setTimeout(f, timeout)
,这显然工作得很好,但是 - 由于各种原因 - 我想避免 JavaScript 代码并单独使用 Elm。
我知道我可以在特定时间间隔 subscribe
到 Tick
并接收时钟滴答声,但这不是我想要的 - 我的延迟没有合理的共同点(例如,其中两个延迟是 30 毫秒和 500 毫秒),我想避免处理很多不必要的滴答声。
我也遇到了 Task
和 Process
- 似乎通过使用它们我可以通过 Task.perform failHandler successHandler (Process.sleep Time.second)
以某种方式实现我想要的。
这有效,但不是很直观 - 我的处理程序只是忽略所有可能的输入并发送相同的消息。此外,我不希望超时永远失败,因此创建失败处理程序感觉就像是在为库提供数据,这不是我对这种优雅语言的期望。
是否有类似 Task.delayMessage time message
的东西可以完全满足我的需要(在指定时间后向我发送其消息参数的副本),或者我是否必须为它制作自己的包装器?
一开始可能不太明显的是,订阅可能会根据模型而变化。每次更新后都会对其进行有效评估。您可以使用这一事实,结合您模型中的某些字段,来控制哪些订阅在任何时候处于活动状态。
这是一个允许 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
.
进行多个不同时间间隔的订阅
如果您希望发生某些事情 "every x seconds",那么您需要一个订阅之类的解决方案,如 @ChadGilbert 所述。 (这或多或少像 javascript 的 setInterval()
。
另一方面,如果您只想 "once, after x seconds" 发生某些事情,那么 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 ]
Elm v0.18 的更新和简化版本是:
delay : Time.Time -> msg -> Cmd msg
delay time msg =
Process.sleep time
|> Task.perform (\_ -> msg)
用法相同
榆木 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
我正在用 Elm 编写一个包含大量时间相关事件的网络游戏,我正在寻找一种在特定时间延迟安排事件的方法。
在 JavaScript 中我使用了 setTimeout(f, timeout)
,这显然工作得很好,但是 - 由于各种原因 - 我想避免 JavaScript 代码并单独使用 Elm。
我知道我可以在特定时间间隔 subscribe
到 Tick
并接收时钟滴答声,但这不是我想要的 - 我的延迟没有合理的共同点(例如,其中两个延迟是 30 毫秒和 500 毫秒),我想避免处理很多不必要的滴答声。
我也遇到了 Task
和 Process
- 似乎通过使用它们我可以通过 Task.perform failHandler successHandler (Process.sleep Time.second)
以某种方式实现我想要的。
这有效,但不是很直观 - 我的处理程序只是忽略所有可能的输入并发送相同的消息。此外,我不希望超时永远失败,因此创建失败处理程序感觉就像是在为库提供数据,这不是我对这种优雅语言的期望。
是否有类似 Task.delayMessage time message
的东西可以完全满足我的需要(在指定时间后向我发送其消息参数的副本),或者我是否必须为它制作自己的包装器?
一开始可能不太明显的是,订阅可能会根据模型而变化。每次更新后都会对其进行有效评估。您可以使用这一事实,结合您模型中的某些字段,来控制哪些订阅在任何时候处于活动状态。
这是一个允许 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
.
如果您希望发生某些事情 "every x seconds",那么您需要一个订阅之类的解决方案,如 @ChadGilbert 所述。 (这或多或少像 javascript 的 setInterval()
。
另一方面,如果您只想 "once, after x seconds" 发生某些事情,那么 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 ]
Elm v0.18
delay : Time.Time -> msg -> Cmd msg
delay time msg =
Process.sleep time
|> Task.perform (\_ -> msg)
用法相同
榆木 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