Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronous @Js is incorrectly implemented. #252

Open
ChenNingCong opened this issue Mar 25, 2020 · 3 comments
Open

Synchronous @Js is incorrectly implemented. #252

ChenNingCong opened this issue Mar 25, 2020 · 3 comments

Comments

@ChenNingCong
Copy link

Related : #156,#150
According to #156, loadurl will cause @js asynchronously return an epmpty dict.
The reason is that,@jsmacro will first lower to a function call js,then js will wrap the jsstring .Since callingloadurl will deactive the page, so this code(from AtomShell/window.jl):

js(win::Window, s::JSString; callback = true) =
  active(win.content) ? js(win.content, s, callback = callback) :
    dot(win, :(this.webContents.executeJavaScript($(s.s))), callback = callback)

will call dot(...),wrap the code in this.webContents.executeJavaScript(code),then it will be sent to AtomShell/main.js and get evaluted by handle.eval
The code handle.eval is that:

handlers.eval = function(data, c) {
  var result = eval(data.code);
  if (data.callback) {
    result == undefined && (result = null);
    result = {
      type: 'callback',
      data: {
        callback: data.callback,
        result: result
      }
    }
    c.write(JSON.stringify(result));
  }
}

The problem is that,executeJavaScript runs asynchronously and it only returns Promise{Any}(see here for more details), so we need to wait for it to return.
A naive fix will be:

handlers.eval = function(data, c) {
  var result = eval(data.code)
  if (data.callback) {
    if ((result!=undefined) && (typeof(result.then)==="function")){
      result.then(function(res){ // we use then to send the results
        res == undefined && (res = null);
        msg = {
          type: 'callback',
          data: {
            callback: data.callback,
            result: res
          }
        }
        c.write(JSON.stringify(msg))
      })
    }
    else{
      result == undefined && (result = null);
      msg = {
        type: 'callback',
        data: {
          callback: data.callback,
          result: result
        }
      }
      c.write(JSON.stringify(msg))
    }
  }
}

Some explanations : since handle.eval is also used to createwindows,so we need to use test whether result is promise. Also the code here doesn't process errors.
On my computer this code works fine and fix #156.

@ChenNingCong
Copy link
Author

Some informations

Julia Version 1.2.0
Commit c6da87ff4b (2019-08-20 00:03 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

Blink:
[ad839575] Blink v0.12.2

@twavv
Copy link
Member

twavv commented Mar 25, 2020

Feel free to open a PR.

The actual change can actually be much simpler. I think the version of Electron we download has native Promises.

// Make this an async function
handlers.eval = async function(data, c) {
  // Await the result (await'ing a non-promise doesn't do anything)
  var result = await eval(data.code);
  /* ... */
}

@ChenNingCong
Copy link
Author

How to handle errors?It seems that wrapping code in a try-catch-finally won't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants