Kris Giesing
Kris Giesing

Reputation: 334

How can stringByEvaluatingJavaScriptFromString be re-entrant?

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?

Upvotes: 1

Views: 166

Answers (1)

Kris Giesing
Kris Giesing

Reputation: 334

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.

Upvotes: 1

Related Questions