5

这是一个打印异步函数结果的客户端 Fable.Remoting 示例。

    // 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价值?

4

3 回答 3

15

我看到你已经用标记了你的问题,所以我假设你已经Msg定义了一个类型。不要使用Async.StartImmediateAsync.RunSynchronously;在 Elmish 中,您应该使用Cmd.OfAsync来安排在异步块返回值后调度消息。有四个函数Cmd.OfAsync(同样的四个也出现在Cmd.OfPromise):eitherperformattemptresult。我会为你分解它们,因为它们的文档还不够成熟:

  • 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 中处理异步生成函数的正确方法。

于 2019-08-23T06:29:32.017 回答
3

return异步是您在 F#中使用的地方之一。所以你需要返回长度值。此外,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# 中有关 Async 的一些资源:

来自 Jet 的 F# 异步指南

异步编程

FSharp 为了乐趣和利润

微软文档

C# 和 F# 异步

于 2019-08-23T05:15:27.217 回答
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。

于 2020-12-28T11:27:18.167 回答