1

I'm building a hybrid native/HTML5 app on iOS. As part of the native/HTML5 bridge, I'm executing some JavaScript code via stringByEvaluatingJavaScriptFromString.

I make sure to call this function from the main dispatch queue on the native side. Most of the time, the effect on the JavaScript side is that the invoked JavaScript code is called directly from the top level (of the JavaScript stack), even if multiple calls to stringByEvaluatingJavaScriptFromString occur in close proximity.

Occasionally, however, I see evidence that a call to stringByEvaluatingJavaScriptFromString occurs during the middle of method execution - that is, a method called by e.g. an event handler doesn't return before the method called by stringByEvaluatingJavaScriptFromString starts to execute.

Given that JavaScript is single-threaded, how is this possible?

Kris Giesing
  • 334
  • 1
  • 15
  • Are you sure the second isn’t just being scheduled? Is your evidence from where native code is being called or when the JavaScript is being evaluated? – Patrick Smith May 28 '15 at 02:53
  • This is in reference to the JavaScript execution stack. See below for the answer (I posted this question just so I could answer it for posterity). – Kris Giesing May 28 '15 at 02:59

1 Answers1

1

This question has been plaguing me for months, and I finally have proof of the answer.

While iOS generally executes stringByEvaluatingJavaScriptFromString calls at the top of the JavaScript stack, there are certain system calls that appear to "yield" to pending evaluations. The one I have specifically identified is XmlHttpRequest.send(): if there happen to be pending evaluations at the time send() is called, send() will block until those evaluations are executed. There may be others as well.

If this behavior is undesirable, you can avoid the re-entrancy of code by wrapping the function invoked by stringByEvaluatingJavaScriptFromString in setTimeout(..., 0). See this question for background information on why such calls can be useful.

Edit: Though it occurs to me after writing this that it's a bit strange that xhr.send() will execute any pending evaluations, but won't execute pending timeouts. I'll have to do some more experiments...

Edit 2: Experiments indicate that xhr.send() does not in fact execute pending timeouts. The inconsistency is a bit odd, but there you have it.

Community
  • 1
  • 1
Kris Giesing
  • 334
  • 1
  • 15