Back in 2019, Alex Zuiev posted to the Claris Community about his discovery that FileMaker’s internal parser seems to cache the JSON data it’s operating on.
For example, if you evaluate the following two expressions, the second one will use the cached value of $jsonA, making it run slightly faster than it otherwise would.
JSONGetElement ( $jsonA ; “alpha” )
JSONGetElement ( $jsonA ; “bravo” )
Alex also discovered that the internal parser caches only one value at a time. There are performance consequences to this under-the-hood behavior. If you extract some values from two different sets of JSON data, the first sequence shown below will perform faster than the second sequence because it will have two cache hits instead of zero:
Sequence 1:
JSONGetElement ( $jsonA ; “alpha” )
JSONGetElement ( $jsonA ; “bravo” ) // cache hit
JSONGetElement ( $jsonB ; “charlie” )
JSONGetElement ( $jsonB ; “delta” ) // cache hit
Sequence 2:
GetElement ( $jsonA ; “alpha” )
JSONGetElement ( $jsonB ; “charlie” )
JSONGetElement ( $jsonA ; “bravo” )
JSONGetElement ( $jsonB ; “delta” )
Another consequence of this behavior is that when extracting values from a large JSON object, we should not delete those elements in a naive attempt to make the operation faster by making the JSON object smaller. Without knowing about caching, it would have been a reasonable assumption that making the JSON object smaller by removing elements that are no longer needed would make subsequent calls to JSONGetElement faster, but that’s not the case due to caching. In fact, doing so would make the overall operation slower.
Code Readability
Alex’s post got me wondering what the effects of JSON caching are for the JSONSetElement function. In particular, I try to write code with a bias for readability, which means I tend to write code like this:
Enter Find Mode [ Pause: Off ]
Set Field [ MyTable::MyField ; “abc” ]
Perform Find [ ]
Instead of like this:
Perform Find [ Restore ]
The first approach has more lines of code, but I can grasp what the script is doing more quickly since I don’t have to open up the script step to see the details.
Similarly, when it comes to JSONSetElement, I would prefer building a JSON object in the following way for the same reason:
Set Variable [ $json ; JSONSetElement ( $json ; "alpha" ; "hello world" ; JSONString ) ]
Set Variable [ $json ; JSONSetElement ( $json ; "bravo" ; "hello world" ; JSONString ) ]
Set Variable [ $json ; JSONSetElement ( $json ; "charlie" ; "hello world" ; JSONString ) ]
Set Variable [ $json ; JSONSetElement ( $json ; "delta" ; "hello world" ; JSONString ) ]
The following is functionally equivalent, but I have to open up the script step to see what’s going on:
Set Variable [ $json ; JSONSetElement ( ""
; [ "alpha" ; "hello world" ; JSONString ]
; [ "bravo" ; "hello world" ; JSONString ]
; [ "charlie" ; "hello world" ; JSONString ]
; [ "delta" ; "hello world" ; JSONString ]
) ]
Granted, gaining that extra bit of readability by making multiple JSONSetElement calls won’t make a game-changing difference. However, in my opinion eliminating little bits of friction where possible adds up to better code, fewer bugs, etc.
Performance Impact of Multiple JSONSetElement Calls
But does calling JSONSetElement multiple times perform more slowly than calling it once?
It sure does. Making multiple calls is significantly slower. (“Significantly” is used in a relative sense here.)
Furthermore, the comparative slowness between the two methods is not constant as you make more and more calls. The slowness accelerates the more times JSONSetElement is called. The chart below shows that while making 10 multiple calls is 5 times slower, making 50 calls is 16 times slower.
Interestingly increasing the size of the value being set doesn’t accelerate the performance degradation. The following chart shows that making 10 multiple calls is about 5-7 times slower, regardless of the size of the value.
Using JSONSetElement Moving Forward
So does that mean that, after observing this behavior, I now always write code using a single JSONSetElement function call? I definitely pay more attention when deciding which approach to use. But while the comparative differences are big, we are still talking about millisecond durations. So for short-running scripts, I still favor readability over performance optimization since users wouldn’t notice the speed improvement anyway. For slower scripts, however, I’m glad to have this optimization technique in my tool belt.
Download the demo if you’d like to run these tests yourself.
Get the Demo File
Next Steps for Your FileMaker Solution
If you’d like more insights into how to make your FileMaker application more efficient, we can help. Contact us to learn more.