我看到你已经用elmish标记了你的问题,所以我假设你已经Msg
定义了一个类型。不要使用Async.StartImmediate
或Async.RunSynchronously
;在 Elmish 中,您应该使用Cmd.OfAsync
来安排在异步块返回值后调度消息。有四个函数Cmd.OfAsync
(同样的四个也出现在Cmd.OfPromise
):either
、perform
、attempt
和result
。我会为你分解它们,因为它们的文档还不够成熟:
either
: 接受四个参数,task
, arg
, ofSuccess
, 和ofError
. task
是您要调用的异步函数(类型为'a -> Async<'b>
)。arg
是'a
要传递给task
函数的类型参数。ofSuccess
是 type 的函数'b -> 'Msg
:它将接收 async 函数的结果,并应该创建一条消息,大概是包含'b
结果的消息。最后,ofError
是一个类型的函数exn -> 'Msg
:如果该task
函数抛出异常,那么ofError
将被调用而不是ofSuccess
,并且应该将该异常转换为您的代码可以处理的 Elmish 消息(可能会将错误记录到 Javascript 控制台或使用Thoth.Toast弹出通知或类似的东西)。
perform
: 喜欢either
,但没有ofError
参数。如果您的异步命令不会失败(远程 API 调用绝不会出现这种情况,因为总是有可能网络已关闭或您的服务器无响应),或者您只是不关心异常并且不介意未处理的异常被抛出。
attempt
: likeeither
但是没有ofSuccess
参数,所以task
如果成功,函数的结果将被忽略。
result
: 这个完全不一样。它只需要一个 type 参数Async<'Msg>
,即你传递给它一个async
已经会产生消息的块。
使用您编写的代码,Cmd.OfAsync.result
如果您想对代码进行最小的更改,您可以使用,但我建议您Cmd.OfAsync.perform
改用(并在Cmd.OfAsync.either
您编写了一些错误处理代码后将其升级)。我将向您展示两种方式:
type Msg =
// ... rest of your messages go here
| GetLength of string
| LengthResult of int
let update msg model =
match msg with
// ... rest of your update function
| GetLength s ->
let usePerform = true
if usePerform then
model, Cmd.OfAsync.perform server.getLength s LengthResult
else
let length : Async<Msg> = async {
let! length = server.getLength s
return (LengthResult length)
}
model, Cmd.OfAsync.result length
| LengthResult len ->
// Do whatever you needed to do with the API result
printfn "Length was %d" len
model, Cmd.none
如果你正在使用either
(一旦你开始生产你真的应该这样做),将会有第三条消息LogError of exn
被处理,如:
| LogError e ->
printfn "Error: %s" e.Message
model, Cmd.none
上面代码中的Cmd.OfAsync.perform
行将变为:
model, Cmd.OfAsync.either server.getLength s LengthResult LogError
这是在 Elmish 中处理异步生成函数的正确方法。