# Performance core principles: 10. Scripting

**URL:** <https://the.fmsoup.org/t/performance-core-principles-10-scripting/1867>\
**Category:** NickLightbody's\
**Tags:** performance, loop\
**Created:** [March 10, 2021, 1:19am UTC](https://the.fmsoup.org/t/performance-core-principles-10-scripting/1867 "2021-03-10T01:19:26Z")\
**Posts on this page:** 1\
**Showing post:** 25

<div class="post-metadata">

**Author:** ![jwilling](https://yyz2.discourse-cdn.com/flex030/user_avatar/the.fmsoup.org/jwilling/32/256_2.png) [@jwilling](https://the.fmsoup.org/u/jwilling)\
**Post date:** [March 31, 2021, 6:44am UTC](https://the.fmsoup.org/t/performance-core-principles-10-scripting/1867/25 "2021-03-31T06:44:03Z")

</div>

I wanted to expand on @mrwatson-de 's fantastic summary. I'll preface by saying these are just my observations (well actually jointly reached with my friend Dan Smith, if he'll allow me to throw him under the bus too).

> [@mrwatson-de](#):
>
> As far as I know the internal JSON cacheing has been present from the start

My experiments suggested caching arrived in v18 (at least with the current behavior).

> [@mrwatson-de](#):
>
> - FileMaker keeps a single copy of the internal objects

That's right. Anytime you call _any_ JSON\* function, FM compares the input **string** to the previous input. If they match _exactly_ (no extra whitespace etc), FM will reuse the cached object. If not, FM overwrites the cache with the new object (this is what you want to avoid doing too much). One nuance here is if you use JSON_ **Set** _Element, the output becomes the new input. So in the following example, $json is modified, and the cache is now based on the modified $json string.

```auto
// $json contains the new input string
Set Variable [$json ; JSONSetElement ( $json ; "height": "6ft" ; JSONString )]

```

> [@mrwatson-de](#):
>
> - build smaller JSON trees before adding them to a larger tree, rather than incrementally adding to a huge tree

Yep. This part is fun. Since the huge JSON object is _cached_, shouldn't it be fast to keep appending it? Not quite: the fact remains, every invocation of a JSON\* function requires FM to read the whole input string just to decide if it can _use_ the cached object (or maybe it reads only up to the first difference). So in this case, it's not the object reading/modifying that's slow, it's the input string comparison.

> [@mrwatson-de](#):
>
> Prefer a _single_ `JSONSetElement` call with multiple parameters over multiple single `JSONSetElements` calls

While true, one of the nice implications of the current caching behavior is that as long as you only work with one JSON object at a time, it can be quite performant to "build up" the JSON in multiple steps because it's not parsing the object each time. E.g. this is pretty chill:

```auto
Set Variable [$json ; JSONSetElement ( "{}" ; "first" ; "Josh" ; JSONString )]
Set Variable [$json ; JSONSetElement ( $json ; "middle" ; "Willing" ; JSONString )]
Set Variable [$json ; JSONSetElement ( $json ; "last" ; "Halpern" ; JSONString )]

```

^ The first step above triggers a parse/cache. The second two steps merely check if $json is the same input (it is, despite the new properties), and reuse the cache.

Personally I'd favor separate JSONSetElement steps in case of optional properties. But be cognizant the input string length, and avoid doing this too much if the JSON was gigantic.

## Bonus

#### JSONGetElement counts as a JSON\* function. So if you _read_ from a second object in between modifying a JSON object, FM will have to re-parse and cache the first object when it gets back to it:

```auto
Set Variable [$name ; JSONGetElement ( $json ; "name" )]
// now $json is parsed
Set variable [$country ; JSONGetElement ( $json ; "country" )]

Set variable [$overwritesCache ; JSONGetElement ( $json2 ; "prop" )]
// now $json2 is cached instead (even though we only did "Get")

// $json will have to be re-parsed/cached
Set Variable [$age ; JSONGetElement ( $json ; "age" )]

```

#### The cached object is scoped to the FM application, not scripts, calculations, windows, or files.

- an object cached in a parent script is available to subscripts (if fed the same input string)
- an object cached in a subscript is available to parents
- the cache outlives the script callstack! So if the input json is the same as the last script called 10 minutes ago it's already cached.
- the cache even survives closing and reopening files. It therefore appears to be FileMaker-scoped.
- the cache doesn't care about your input string _source_. If you have $json cached and you copy that variable to $json2, then `JSONGetElement ( $json2 ; ... )` will use the cache. You can also read the value from a field with the same effect.

One sneaky gotcha here is if you are setting one json object using properties from another, this can be cause a lot of re-parsing if done in, say, a loop, because you keep overwriting the cache with each step:

```auto
Set Variable [$value ; JSONGetElement ( $source ; "name" )]
Set Variable [$target ; JSONSetElement ( $target ; "name" ; $value ; JSONString )]
Set Variable [$value ; JSONGetElement ( $source ; "dob" )]
Set Variable [$target ; JSONSetElement ( $target ; "dob" ; $value ; JSONString )]

```

Whew, hope you don't mind an impromptu essay!  
J

---

_[View the full topic](https://the.fmsoup.org/t/performance-core-principles-10-scripting/1867)._
