我们可以使用js_of_ocaml来包装JS函数,从而在OCaml中调用它。当JS函数是异步的时(即包括promises并花费时间),我无法做一个有用的例子。
我要包装的异步JS函数JSfun
如下所示。变量x
在2秒后设置为"here"
,这是我想要返回的值。
function JSfun() {
var x = "before";
return new Promise(function(resolve, reject) {
setTimeout(function() {
append("inside setTimeout");
x = "here";
resolve(x);
}, 2000);
})
}
我们可以在JS中成功调用JSfun
并按预期获得"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")
);
那么有没有人有解决方案,想法或解决方法?
答案 0 :(得分:1)
如果你的js函数是异步的,你的OCaml对应函数也应该是异步的,即它应该使用Lwt或Async。因此,对于Lwt,您可能会使用Lwt.task
来创建休眠线程和唤醒器,然后使用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