避免在榆树中遇到Http Race Condition

时间:2018-01-08 15:15:21

标签: elm

假设我们有一个文本输入字段,并且在其内容的每次更改时,我们都会向搜索API发送Http请求。现在,我们无法保证Http响应按照我们发送请求的顺序返回elm。

确保我们对与最新请求相对应的响应做出最简单的反应的最简单方法 - 而不是最新回复,这可能对应于过时的搜索字符串?是否有一种简单的方法将查询字符串附加到Elm的http效果返回的消息中?或者我们可以将响应链接到触发请求的任何其他方式?

如果可能,我希望避免将查询包含在搜索API的响应中。另一种解决方法是去除搜索,但这只会降低使用错误响应的可能性,而我们希望消除它。

感谢您的帮助!

示例:

import Html
import Html exposing (..)
import Html.Events exposing (onClick, onInput)
import Http
import Json.Decode as Decode


main = Html.program
        { init = ( { searchText = "", result = "" }, Cmd.none )
        , update = update
        , subscriptions = (\model -> Sub.none)
        , view = view
        }


type alias Model =
    { searchText : String
    , result: SearchResult  
    }


type alias SearchResult = String


type Msg 
    = NewSearchText String
    | ReceivedResponse (Result Http.Error SearchResult)


update msg model = 
    case msg of 

        NewSearchText newText ->
            ( { model | searchText = newText}
            , getSearchResult newText
            )

        ReceivedResponse (Result.Ok response) ->
            ( { model | result = response }
            , Cmd.none
            ) 

        ReceivedResponse (Result.Err error) ->
            Debug.crash <| (toString error)



getSearchResult : String -> Cmd Msg
getSearchResult query =
    let 
        url = "http://thebackend.com/search?query=" ++ query

        request : Http.Request SearchResult  
        request = Http.get url Decode.string
    in
        Http.send ReceivedResponse request            


view model =
    div [] 
        [ Html.input [onInput (\text -> NewSearchText text)] []
        , Html.text model.result
        ]

2 个答案:

答案 0 :(得分:7)

是的,可以将查询字符串附加到响应中。首先,扩充您的消息类型以处理其他数据:

type Msg 
  = NewSearchText String
  | ReceivedResponse String (Result Http.Error SearchResult)

然后,更改Http.send来电,将查询文字附加到ReceivedResponse消息:

Http.send (ReceivedResponse query) request

最后,在update中,在结果Msg上的模式匹配中抓取查询:

case msg of
  ReceivedResponse query (Ok response) ->
    ...
  ReceivedResponse query (Err err) ->
    ...

为什么这样做?

Http.send函数的第一个参数可以是一个消耗Result Http.Error SearchResult并将其变为Msg的任意函数。在原始代码中,该函数只是ReceivedResponse,即Msg构造函数。更新Msg类型以便ReceivedResponse获取两个参数时,ReceivedResponse构造函数变为一个curried双参数函数,而ReceivedResponse "some query here"是一个 - 参数函数接收Result并返回Msg

答案 1 :(得分:5)

以这种方式:

在模型中添加两​​个整数:

  1. requestsSent : Int - 提出的请求数量。
  2. lastReceived : Int - 您已处理的最新请求。
  3. 修改ReceivedResponse以将Int作为第一个值:

    | ReceivedResponse Int (Result Http.Error SearchResult)
    

    现在,无论何时发出请求,都要在模型中将requestsSent增加1,然后按&#34;标记&#34;部分应用ReceivedResponse

    的请求
    Http.send (ReceivedResponse model.requestsSent) request
    

    update功能中,检查Int中的ReceivedResponse是否大于lastReceived。如果是,请对其进行处理,并将lastReceived的值设置为此响应的Int。如果不是,请丢弃它,因为您已经处理了较新的请求。