这里是一个客户端寓言。远程处理示例显示了异步功能的结果。
// Client code (Compiled to Javascript using Fable)
// ============
open Fable.Remoting.Client
let server = Proxy.create<IServer>
async {
let! length = server.getLength “hello”
do printfn “%d” length // 5
}
|> Async.StartImmediate
如何获取length
值?
答案 0 :(得分:5)
我看到您已经用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
是类型'b -> 'Msg
的函数:它将接收异步函数的结果,并应创建一条消息,大概是包含'b
结果的消息。最后,ofError
是类型为exn -> 'Msg
的函数:如果task
函数引发异常,则将调用ofError
而不是ofSuccess
,并且假定将该异常转化为代码可以处理的Elmish消息(可能是将错误记录到Javascript控制台或弹出带有Thoth.Toast或类似内容的通知的消息)。perform
:类似于either
,但没有ofError
参数。如果您的异步命令无法失败(远程API调用永远不会发生这种情况,因为它总是有可能发生网络故障或您的服务器无响应),或者您只在乎异常而不在乎,请使用此选项引发未处理的异常。attempt
:类似于either
,但没有ofSuccess
参数,因此如果成功,task
函数的结果将被忽略。result
:这是完全不同的。它只需要一个Async<'Msg>
类型的参数,即,您将已经产生消息的async
块传递给它。使用您编写的代码,如果您想对代码进行最少的更改,则可以使用Cmd.OfAsync.result
,但是我建议使用Cmd.OfAsync.perform
代替(并将其升级为{{1} }一旦编写了一些错误处理代码)。我将向您展示两种方式:
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
这是处理Elmish中异步生成功能的正确方法。
答案 1 :(得分:2)
异步是您在F#中使用return
的地方之一。因此,您需要返回长度值。同样,Async.StartImmediate
返回()
(单位)。使用其他东西,例如Async.RunSynchronously
,如果您需要提取的值。取决于您需要使用它来实现什么。
let length =
async {
let! length = async {return String.length "hello"}
do printfn "%d" length // 5
return length
} |> Async.RunSynchronously
length // val it : int = 5
顺便说一句,你提到寓言。因此,您也许可以使用JS promise
。
有关F#中异步的一些资源:
答案 2 :(得分:2)
对于那些想从 js 代码中调用的人。
// Client code (Compiled to Javascript using Fable)
// ============
open Fable.Remoting.Client
open Fable.Core // required for Async.StartAsPromise
let server = Proxy.create<IServer>
let len_from_fable () =
async {
let! length = server.getLength “hello”
return length
} |> Async.StartAsPromise
从js调用
async func() {
let len = await len_from_fable()
print(len)
}
适用于寓言 3.0。