Funscript和Async.RunSynchronously

时间:2013-10-27 23:02:48

标签: asynchronous f# funscript

我正在玩Funscript,希望得到一些我工作流程的结果。 我将那些天真的定义(没有结果单元格)添加到异步模块。

   static member RunSynchronously(workflow:Async<'T>, ?timeout:int,?cancellationToken:CancellationToken) =
      let result = ref None
      let token = defaultArg cancellationToken { Cell = None }
      let (Cont f) = workflow
      let aux = { StackCounter = ref 0; ExceptionCont = ignore; 
                  CancelledCont = ignore; CancellationToken = token }
      f { Cont = (fun v -> result :=  Some v); Aux = aux }
      let r = !result
      r.Value

   static member StartChild(computation:Async<'T>,?millisecondsTimeout:int) = 
      async { return Async.FromContinuations(fun (cont, econt,ccnt) -> cont (Async.RunSynchronously computation))           }

在这种情况下适用

   let test =  async{  let t = async { let! r = async { return "inside" }
                                       return "Hello" } 
                       let! task = Async.StartChild t
                       let! res = task
                       return res   
                    } |> Async.RunSynchronously 

但是当被问及“真实”时会摔倒

  let toto = Globals.document.createElement_img()
   toto.id <- "toto"
   Globals.document.body.appendChild(toto :> Node) |> ignore
   let test =  async{  let t = async { let! r = Async.AwaitJQueryEvent(j?toto.load)
                                       return "Hello" } 
                       let! task = Async.StartChild t
                       do toto.src <- "redundant.png"
                       let! res = task
                       return res   
                    } |> Async.RunSynchronously 

因为j?toto.load方法没有挂起并回拨给我,并且打破了异步流。我猜这就是用单线程javascript做的事情。

什么是真正的解决方案? 像F#一样实施超支是唯一的方法吗?

1 个答案:

答案 0 :(得分:3)

异步工作流的FunScript实现不使用当今JS中可用的任何高级线程机制。它只是在主浏览器线程上运行所有内容 - 这也是它为Async.StartImmediate提供映射的原因,因为这在逻辑上与标准F#运行时中的这种行为相对应。

如果你想启动一个等待事件然后同步运行的工作流,那么这个模型就不可能了 - 所以你不能合理地实现永远有效的RunSynchronously(到同步运行,你需要阻止当前线程,但是你不能等待事件......)

所以,我认为你需要以某种方式重构你的代码,这样它就不需要同步等待 - 可能也是让调用者异步。