fabulous-dev / Fabulous

Declarative UI framework for cross-platform mobile & desktop apps, using MVU and F# functional programming
https://fabulous.dev
Apache License 2.0
1.13k stars 122 forks source link

Add Async.executeOnMainThread #950

Closed TimLariviere closed 2 years ago

TimLariviere commented 2 years ago

Fixes #946

By default, Cmds in Fabulous 2.0 are not executed on the main UI thread for performance reasons. If you need to execute some logic on the UI thread, you can use the new Async.executeOnMainThread.

let showAlertCmd =
    async {
        do! Application.Current.MainPage.DisplayAlert("An alert!", "OK")
        return AlertShown
    }
    |> Async.executeOnMainThread
    |> Cmd.ofAsyncMsg
TimLariviere commented 2 years ago

@kevkov I think the issue you found is related to the fact Task is executed as soon as it is created while Async waits for Fabulous to execute it.

So doing this was not working:

let task = (...) // the task is executed immediately on the current thread

task
|> Async.AwaitTask // convert the running task into Async
|> Async.executeOnMainThread // ask to execute the return of the task into the UI Thread

Instead you need to put the task inside an async computation

async {
    let! result = (...) // the task. Will only be executed when the parent async comp. is executed
}
|> Async.executeOnMainThread
edgarfgp commented 2 years ago

Maybe a little overkill but . What do you think about a ce ?

  type MainThreadBuilder() =
        member this.Zero() =
            printf "Zero"
            ()

        member this.Delay(f) = 
            DispatchQueue.MainQueue.DispatchAsync(fun _ ->  f())

    let mainThread = MainThreadBuilder()

   mainThread {
   // Code goes here 
  } 
twop commented 2 years ago

@edgarfgp I think it might be an overkill, CE are awesome when they provide a unique ergonomic value (e.g. hard to express intent otherwise) and should be use sparingly (IMHO). I think the main concern I have is when you have multiple different CE within the same code block, that does introduce significant overhead to parse the intent. Again, "in my humble opinion".

TimLariviere commented 2 years ago

I agree with @twop. Having a CE for this wouldn't make much sense and would confuse users. An helper function is enough here.