|
7 | 7 |
|
8 | 8 | We can do this by marking the field with the `@tracked` decorator.
|
9 | 9 |
|
| 10 | + ### Caching a getter value |
| 11 | +
|
| 12 | + The `@cached` decorator can be used on getters in order to cache the |
| 13 | + return value of the getter. |
| 14 | +
|
| 15 | + This method adds an extra overhead to each memoized getter, therefore caching |
| 16 | + the values should not be the default strategy, but used in last resort. |
| 17 | +
|
10 | 18 | @module @glimmer/tracking
|
11 | 19 | @public
|
12 | 20 | */
|
|
146 | 154 | @for @glimmer/tracking
|
147 | 155 | @public
|
148 | 156 | */
|
| 157 | + |
| 158 | +/** |
| 159 | + Gives the getter a caching behavior. The return value of the getter |
| 160 | + will be cached until any of the properties it is entangled with |
| 161 | + are invalidated. This is useful when a getter is expensive and |
| 162 | + used very often. |
| 163 | +
|
| 164 | + For instance, in this GuestList class, we have the sortedGuests |
| 165 | + getter that sorts the guests alphabetically: |
| 166 | +
|
| 167 | + ```javascript |
| 168 | + import { tracked } from '@glimmer/tracking'; |
| 169 | +
|
| 170 | + class GuestList { |
| 171 | + @tracked guests = ['Zoey', 'Tomster']; |
| 172 | +
|
| 173 | + get sortedGuests() { |
| 174 | + return this.guests.slice().sort() |
| 175 | + } |
| 176 | + } |
| 177 | + ``` |
| 178 | +
|
| 179 | + Every time sortedGuests is accessed, a new array will be created and sorted, |
| 180 | + because JavaScript getters do not cache by default. When the guest list |
| 181 | + is small, like the one in the example, this is not a problem. However, if |
| 182 | + the guest list were to grow very large, it would mean that we would be doing |
| 183 | + a large amount of work each time we accessed sortedGetters. With @cached, |
| 184 | + we can cache the value instead: |
| 185 | +
|
| 186 | + ```javascript |
| 187 | + import { tracked, cached } from '@glimmer/tracking'; |
| 188 | +
|
| 189 | + class GuestList { |
| 190 | + @tracked guests = ['Zoey', 'Tomster']; |
| 191 | +
|
| 192 | + @cached |
| 193 | + get sortedGuests() { |
| 194 | + return this.guests.slice().sort() |
| 195 | + } |
| 196 | + } |
| 197 | + ``` |
| 198 | +
|
| 199 | + Now the sortedGuests getter will be cached based on autotracking. |
| 200 | + It will only rerun and create a new sorted array when the guests tracked |
| 201 | + property is updated. |
| 202 | +
|
| 203 | + ### Tradeoffs |
| 204 | +
|
| 205 | + Overuse is discouraged. |
| 206 | +
|
| 207 | + In general, you should avoid using `@cached` unless you have confirmed that |
| 208 | + the getter you are decorating is computationally expensive. `@cached` adds |
| 209 | + a small amount of overhead to the getter, making it more expensive. |
| 210 | + While this overhead is small, if `@cached` is overused it can add up to a |
| 211 | + large impact overall in your app. Many getters and tracked properties |
| 212 | + are only accessed once, rendered, and then never rerendered, so adding |
| 213 | + `@cached` when it is unnecessary can negatively impact performance. |
| 214 | +
|
| 215 | + Also, `@cached` may rerun even if the values themselves have not changed, |
| 216 | + since tracked properties will always invalidate even if their underlying |
| 217 | + value did not change. |
| 218 | + For example updating an integer value from `5` to an other `5`. |
| 219 | +
|
| 220 | + Avoiding a cache invalidation in this case is not something that can |
| 221 | + be achieved on the `@cached` decorator itself, but rather when updating |
| 222 | + the underlying values, by applying a diff checking mecanism: |
| 223 | +
|
| 224 | + ```javascript |
| 225 | + if (newValue !== this.trackedProp) { |
| 226 | + this.trackedProp = newValue; |
| 227 | + } |
| 228 | + ``` |
| 229 | +
|
| 230 | + Here equal values won't update the property, therefore not triggering a |
| 231 | + cache invalidation. |
| 232 | +
|
| 233 | + The cost of these edge-guards adds up to the tradoff calculation of using |
| 234 | + a caching strategy, hence requiring a very sensitive approach regarding |
| 235 | + performance. |
| 236 | +
|
| 237 | + @method cached |
| 238 | + @static |
| 239 | + @for @glimmer/tracking |
| 240 | + @public |
| 241 | +*/ |
0 commit comments