Skip to content

Asynchronous versus Synchronous Communication

Thomas Thomassen edited this page Jan 6, 2014 · 7 revisions

Asynchronous versus Synchronous Communication

This is an issue which often cause trouble since there are differences in how OSX communicates between Ruby and the WebDialog's JavaScript.

JavaScript to Ruby

Here is a short snippet to demonstrate the differences:

Ruby

module Example
  def self.call_me
    path = File.dirname(__FILE__)
    dialog = UI::WebDialog.new()
    dialog.set_file( File.join(path, 'async.html') )
    dialog.show {
      puts "WebDialog.show"
      dialog.add_action_callback("callme") { |wd, param|
        puts "callme(#{param.inspect})"
      }
      puts ".execute_script:"
      dialog.execute_script('call_me();')
    } # show
    dialog
  end
end

HTML

<!DOCTYPE html>
<html>
<head>
<script>
function call_me() {
  for (i = 1; i < 6; i++) {
    window.location='skp:callme@HelloWorld'+i;
  }
}
</script>
</head>
<body>
<code>Example.call_me</code>
</body>
</html>

Windows

Under Windows the communication between JavaScript and Ruby is synchronous.

That means when you call a ruby method using window.location = 'skp:rubyMethod', the javascript will wait for the ruby method to complete before proceeding with the next javascript statement.

In the above example the result is:

w = Example.call_me
#<UI::WebDialog:0x10a6317c>
WebDialog.show
.execute_script:
callme("HelloWorld1")
callme("HelloWorld2")
callme("HelloWorld3")
callme("HelloWorld4")
callme("HelloWorld5")

OSX

Under OSX it just sends the command and continues with the JavaScript without waiting - making it impossible call sequential callbacks to ruby too quickly as they will override each other.

In the above example the result is:

w = Example.call_me
#<UI::WebDialog:0x10a6317c>
WebDialog.show
.execute_script:
callme("HelloWorld5")

Workaround: Message Pump

The JavaScript side needs to stack out messages going to Ruby and only dispatch the next message after the Ruby side has confirmed the previous message was received.

TODO: Upload sample code for a message pump.

Ruby to JavaScript

Calling from Ruby to JavaScript using .execute_script is synchronous on both platforms. The method will wait for the JavaScript to finish before processing next line of ruby.

So you can do stuff like this:

HTML

<input id="sketchupPump" type="hidden">

JavaScript

function add(n1, n2)
{
  document.getElementById('sketchupPump').value = n1 + n2;
}

Ruby

dialog.execute_script('add(2,3);')
value = dialog.get_element_value('sketchupPump')

The add JavaScript function will here take both arguments and add them together and put the value into a hidden input field with the id 'sketchupPump'.

Further reading