web-dev-qa-db-ja.com

ElmでsetTimeoutの動作を実現する方法

Elmで時間依存のイベントがたくさんあるWebゲームを書いていて、特定の時間遅延でイベントをスケジュールする方法を探しています。

JavaScriptではsetTimeout(f, timeout)を使用しましたが、これは非常にうまく機能しましたが、さまざまな理由により、JavaScriptコードを避け、Elmだけを使用したいと考えています。

特定の間隔でsubscribeからTickを取得してクロックティックを受け取ることができることは承知していますが、これは私が望んでいることではありません。遅延は30ミリ秒と500ミリ秒です)、多くの不要なティックを処理する必要がないようにしたいと思います。

私はTaskProcessにも出会いました-それらを使用することで、Task.perform failHandler successHandler (Process.sleep Time.second)で何とかしたいようです。

これは機能しますが、あまり直感的ではありません。私のハンドラーは、可能なすべての入力を無視して同じメッセージを送信するだけです。さらに、私はタイムアウトが失敗することを期待していません。そのため、失敗ハンドラーを作成することは、ライブラリーにフィードを送るようなものです。これは、このようなエレガントな言語に期待するものではありません。

Task.delayMessage time messageのようなものはありますか?それは、私が必要とすることを正確に実行しますか(指定された時間の後にメッセージ引数のコピーを送ってください)、または独自のラッパーを作成する必要がありますか?

23
Tomasz Lewowski

最初は明らかではないかもしれませんが、サブスクリプションはモデルに基づいて変更できるという事実です。更新のたびに効果的に評価されます。この事実をモデル内のいくつかのフィールドと組み合わせて使用​​して、どのサブスクリプションがいつアクティブになるかを制御できます。

可変カーソルの点滅間隔 を許可する例を次に示します。

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

私があなたの懸念を理解していれば、これは不要なティックを処理する可能性を克服するはずです。 Sub.batchを使用すると、異なる間隔の複数のサブスクリプションを持つことができます。

24
Chad Gilbert

@ wintveltの答え の更新および簡略化されたバージョンは、次のとおりです。

delay : Time.Time -> msg -> Cmd msg
delay time msg =
  Process.sleep time
  |> Task.perform (\_ -> msg)

同じ使用法で

32
user6996876

「x秒ごと」に何かを実行したい場合は、@ ChadGilbertが説明するサブスクリプションのようなソリューションが必要です。 (多かれ少なかれjavascriptのsetInterval()に似ています。

一方、「x秒後に1回だけ」何かを実行したい場合は、_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 ]
_
25
wintvelt