当道具发生变化时,如何取消 Cmd.OfAsync?

sdg*_*sdh 5 f# elmish

假设我有一个受控的埃尔米语形式:

type Model = 
  {
    Query : string
    IsLoading : bool
    Result : Result<QueryResults, string> option
  }

type Message =
  | UpdateQuery of string
  | ReceivedResults of Result<QueryResults, string>

let update message model = 
  match message with
  | UpdateQuery query ->
    let nextModel =
      {
        model with
          Query = query
          IsLoading = true
      }

    let cmd = 
      Cmd.OfAsync.result (async {
        let! results = Api.tryFetchQueryResults query

        return ReceivedResults results
      })

    nextModel, cmd
  | ReceivedResults results ->
    {
      model with
        IsLoading = false
        Results = Some results
    }, Cmd.none
Run Code Online (Sandbox Code Playgroud)

每次model.Query发生变化时,它都会发出一个async请求。但是,如果已经有一项请求正在进行中,我希望取消该请求并替换为新请求。

在 Elmish 中执行此操作的好方法是什么?

nil*_*irk 2

没有内置任何东西来支持底层的取消XMLHttpRequest

然而,我们可以构建一些小型机器来支持类似取消的功能:

首先,使用Model有关当前待处理查询的信息来扩充您的信息,并Message使用该查询的链接(一个简单的Guid操作)来扩充您的信息

open System

type Model = 
  {
    Query : string
    IsLoading : bool
    Result : Result<QueryResults, string> option
    PendingQuery: Guid option
  }

type Message =
  | UpdateQuery of string
  | ReceivedResults of Guid * Result<QueryResults, string>
Run Code Online (Sandbox Code Playgroud)

update接下来,在您的函数中提供这些数据

  | UpdateQuery query ->

    let correlationId = Guid.NewGuid()

    let nextModel =
      {
        model with
          Query = query
          IsLoading = true
          PendingQuery = Some correlationId
      }

    let cmd = 
      Cmd.OfAsync.result (async {
        let! results = Api.tryFetchQueryResults query

        return ReceivedResults (correlationId, results)
      })

    nextModel, cmd
Run Code Online (Sandbox Code Playgroud)

最后,在从服务器接收数据时检查待处理的查询并忽略与链接不匹配的内容

  | ReceivedResults (correlationId, results) ->
    match model.PendingQuery with
    | Some id when id = correlationId ->
      {
        model with
          IsLoading = false
          PendingQuery = None
          Result = Some results
      }, Cmd.none
    | _ -> model, Cmd.none
Run Code Online (Sandbox Code Playgroud)