Можно ли обернуть асинхронную функцию JS и использовать ее в OCaml?
Мы могли бы использовать js_of_ocaml, чтобы обернуть JS-функцию и, таким образом, вызвать ее в OCaml. Я не могу сделать рабочий пример, когда функция JS является асинхронной (то есть включает в себя обещания и требует времени).
Асинхронная функция JS JSfun
Я хочу завернуть это следующим образом. Переменная x
установлен в "here"
через 2 секунды, и это значение, которое я хочу вернуть.
function JSfun() {
var x = "before";
return new Promise(function(resolve, reject) {
setTimeout(function() {
append("inside setTimeout");
x = "here";
resolve(x);
}, 2000);
})
}
Мы могли бы успешно позвонить JSfun
в JS и получить "runJS here"
как и ожидалось:
function runJS() {
JSfun().then(function(res) {
append("runJS " + res)
})
}
Тем не менее, OCaml трудно имитировать эту цепочку. Обернуть JSfun
в OCaml кажется, что мы должны использовать:
Js.Unsafe.global##.OCamlcall := Js.wrap_callback
(fun _ ->
let m = Js.Unsafe.fun_call (Js.Unsafe.js_expr "JSfun") [||] in
Js.string ((Js.to_string m) ^ " Via OCaml")
);
И у меня нет другой идеи, кроме как звонить так:
function runOCaml() {
var res = OCamlcall("abc");
append(res);
}
Неудивительно, что это не работает: мы видим "inside setTimeout"
напечатано, что доказывает JSfun
был вызван, но возвращаемого значения не было.
Вот это jsfiddle. Я также делаю рабочий пример обтекания синхронной функции JS. В OCaml упаковка выглядит так:
Js.Unsafe.global##.OCamlcallSync := Js.wrap_callback
(fun _ ->
let m = Js.Unsafe.fun_call (Js.Unsafe.js_expr "JSfunSync") [||] in
Js.string ((Js.to_string m) ^ " Via OCaml")
);
Так есть ли у кого-нибудь решение, идея или обходной путь?
1 ответ
Если ваша функция js асинхронная, ваш аналог OCaml также должен быть асинхронным, то есть использовать Lwt или Async. Итак, для Lwt вы, вероятно, будете использовать Lwt.task
создать спящий поток и wakener, а затем передать обратный вызов с wakener в Promises' .then
метод и вернуть спящий поток из вашей функции.
Код будет выглядеть так (некоторые типы, вероятно, слишком общие):
class type promise =
object
method then_ : ('a -> 'b) callback -> 'b meth
end
let ocamlcall () =
let t, w = Lwt.task () in
let wakeup = Js.wrap_callback (fun r -> Lwt.wakeup t r) in
let (promise : promise Js.t) = Js.Unsafe.fun_call jsfunc [||] in
let () = ignore @@ promise##then_ wakeup in
t
Примечание: я не тестировал этот код, но он должен дать вам общее представление о том, как взаимодействовать с асинхронными js-функциями.
Вы также можете проверить, как jsoo работает с jsonp, например: https://github.com/ocsigen/js_of_ocaml/blob/master/lib/jsonp.ml