Funscript и Async.RunSynchronously
Я играл с Funscript и хотел получить какой-то результат обратно в свой рабочий процесс. Я добавил эти наивные определения (без ячейки результата) в модуль Async.
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.
Каково было бы реальное решение этого? Будет ли реализация supensions, как в F#, единственным способом?
1 ответ
Реализация асинхронных рабочих процессов в FunScript не использует каких-либо расширенных механизмов потоков, которые могут быть доступны в JS сегодня. Он просто запускает все в главном потоке браузера - и это также причина, почему он обеспечивает отображение только для Async.StartImmediate
потому что это то, что логически соответствует этому поведению в стандартной среде выполнения F#.
Если вы хотите запустить рабочий процесс, который ожидает событие, а затем запустить его синхронно, то это не будет возможно в этой модели - и поэтому вы не можете разумно реализовать RunSynchronously
это всегда будет работать (для синхронной работы вам нужно заблокировать текущий поток, но тогда вы не можете ждать событий...)
Итак, я думаю, что вам нужно каким-то образом реструктурировать свой код, чтобы он не нуждался в синхронном ожидании - возможно, также сделав вызывающий объект асинхронным.