2017-03-11 2 views
1

私は、同期して2つの投稿要求を送信する必要があり、第2の応答は第1の応答に依存しますが、問題は第1の応答が送信される前でもHTTP要求を送信中の競合状態

update : msg -> model -> (model, Cmd msg) 
update msg m = 
    case msg of 

    ... 

    Submit -> (m, 
     send FirstResp <| post "/resource1" 
      (jsonBody <| encoderX m) int) 
    FirstResp (Ok x) -> ({m | pid = x}, 
     send SecondResp <| post "/resource2" 
      (jsonBody <| encoderY m) int) 

    ... 

私はそれを数回テストしました。サーバーが最初の投稿で3を指定した場合、pid0として送信されますが、もう一度送信すると、3としてpidが送信され、サーバーからの回答は、たとえば、4は無視されます。

値を割り当てるのを待機するにはどうすればよいですか?

答えて

4

elmのデータ構造は変更不可能{m | pid = x}であるため、mは変更されませんが、新しいレコードが返されます。したがって、2回目のリクエストに渡すと更新されたモデルはありません。二回{m | pid = x}を使用して

はあなたが捜している結果を得るでしょう(それは非常にきれいではありません)あなたが要求を送信する前に、変数に新しいモデルを保存するためにlet inを使用することができます

FirstResp (Ok x) -> ({m | pid = x}, 
    send SecondResp <| post "/resource2" 
     (jsonBody <| encoderY {m | pid = x}) int) 

。今すぐモデルを変更する場合は、1か所だけ見る必要があります。

FirstResp (Ok x) -> 
    let 
     newM = {m | pid = x} 
    in 
     (newM, send SecondResp <| post "/resource2" 
     (jsonBody <| encoderY newM) int) 

あなたも、よりよい解決策は、チェーンにTask.andThenとのリクエストになり、モデル内の最初のリクエストの結果を必要としない場合。これにより、2つの別々のメッセージ(FirstResp、SecondResp)は必要ありません。

request1 m = 
    post "/resource1" (jsonBody <| encoderX m) int) 
     |> Http.toTask 

request2 m = 
    post "/resource1" (jsonBody <| encoderX m) int) 
     |> Http.toTask 

Submit -> 
    (m 
    , request1 m 
     |> Task.andThen request2 
     |> Task.attempt Resp 
    ) 

Resp (Ok res2) -> 
    -- res2 is the result of your request2 

あなたは、両方の結果が必要な場合は、タプルにそれらをマッピングし、更新機能でそれを抽出することができます。

Submit -> 
    (m 
    , request1 m 
     |> Task.andThen 
      (\res1 -> request2 res1 
       |> Task.map ((,) res1) 
      ) 
     |> Task.attempt Resp 
    ) 

Resp (Ok (res1, res2) -> 
    -- use res1 and res2 

Elm packages - Task