我正在玩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#一样实施超支是唯一的方法吗?
答案 0 :(得分:3)
异步工作流的FunScript实现不使用当今JS中可用的任何高级线程机制。它只是在主浏览器线程上运行所有内容 - 这也是它为Async.StartImmediate
提供映射的原因,因为这在逻辑上与标准F#运行时中的这种行为相对应。
如果你想启动一个等待事件然后同步运行的工作流,那么这个模型就不可能了 - 所以你不能合理地实现永远有效的RunSynchronously
(到同步运行,你需要阻止当前线程,但是你不能等待事件......)
所以,我认为你需要以某种方式重构你的代码,这样它就不需要同步等待 - 可能也是让调用者异步。