Scope of JavaScript Objects

In a previous post, I went into the details of how XFA objects are integrated with the JavaScript interpreter.  One of the challenges in integrating the XFA object model with JavaScript has been determining how long to keep objects/variables in scope.  Keeping too many objects in scope leads to high memory usage and performance issues.  To get a sense of the size of the problem, bear in mind that it is not just fields and subforms that result in JavaScript objects, but their properties as well.  A script that accesses field.border.fill will create three JavaScript object references.  When you multiply the number of fields and subforms by the number of properties that can be accessed via script, you can see that there is potential to create an unwieldy number of XFA object references in JavaScript. 

JavaScript Variable Cleanup

We wanted to change the Reader to clean up JavaScript object references more aggressively, but we couldn’t change the default behaviour without breaking existing forms.  The solution was to expose strict scoping rules as an option in Designer:

image

This setting allows us to change form behaviours to clean up object references more frequently.  Strict scoping was first available for forms targeting Reader 8.1.  However, in 8.1, the cleanup was more aggressive than necessary.  Reader 8.1 released references to *all* JavaScript variables after each script execution.  In Reader 9 we eased off a bit and no longer release JavaScript variables declared in XFA Script Objects. 

As a result, when targeting forms for 8.1 with strict scoping on, you need to make all your XFA Script Objects re-entrant.  Do not rely on JavaScript variables sticking around.  You might not immediately realize that your variable references have been released, since they will continue to work until the JavaScript engine decides to perform its garbage collection.

Private Properties

I have seen customers defining script that looks like this:

MyField.myCustomProperty = "hello world";

What happens here is that the JavaScript interpreter does what is expected for any JavaScript object — it adds a new property to the object hash map.  This coding practise is pretty attractive when you consider the benefits of associating arbitrary JavaScript variables or functions with XFA objects. 

But there is a problem — associating new properties with JavaScript object references requires keeping those JavaScript objects in scope.  Since with strict scoping the JavaScript references are released, the private properties are also lost.  Rather than have people discover this the hard way by having variables mysteriously disappear at random intervals (during garbage collection), Reader 9 will issue an error when script attempts to assign an unknown property — when strict scoping is on.

Recommendation

The non-strict mode of variable management will continue to be supported, but I do not recommend relying on those behaviours.  I recommend strict scoping for a couple of reasons:

  1. Bug fixes:  We have branched our code internally to take one path for strict scoping (variable cleanup) and a separate path for non-strict scoping.  Going forward, only the strict scoping code path will get script bug fixes.
  2. Scalable Design Patterns:  When creating script-intensive large forms with non-strict scoping you are liable to eventually run into the performance issues of too many JavaScript objects.  My preference is (where possible) to use design patterns that work well with both small and large forms.

My preferred alternative is to use form variables on subforms and the desc or extras elements on fields as described in a previous post.