0

我们可以使用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);
  })
}

我们可以成功调用JSfunJS 并按"runJS here"预期得到:

function runJS() {
  JSfun().then(function(res) {
    append("runJS " + res)
  })
}

但是,OCaml 很难模仿这种链接。要包装JSfunOCaml,似乎我们必须使用:

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"print 了,这证明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")
    );

那么有人有解决方案、想法或解决方法吗?

4

1 回答 1

1

如果你的 js 函数是异步的,那么你的 OCaml 对应函数也应该是异步的,即它应该使用 Lwt 或 Async。因此,对于 Lwt,您可能会使用Lwt.task创建休眠线程和唤醒器,然后将带有唤醒器的回调传递给 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

于 2016-07-13T13:49:16.870 回答