# Any tips for caching/improving performance of Decorations?

**URL:** https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044
**Category:** Uncategorized
**Created:** [December 14, 2024, 6:42pm UTC](https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044 "2024-12-14T18:42:05Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![spaceemotion](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/spaceemotion/32/4178_2.png) [@spaceemotion](https://discuss.prosemirror.net/u/spaceemotion)
#### Post date: [December 14, 2024, 6:42pm UTC](https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044/1 "2024-12-14T18:42:05Z")

</div>

We use decorations to highlight words and basically add “real-time” links to text (e.g. annotations, spellcheck markers, etc.). This means that the plugin runs over the full text on all transactions that change the content in some way.

I came across [Decorations performance - #5 by marijn](https://discuss.prosemirror.net/t/decorations-performance/2381/5) which says to store the decorations in a plugin state, but even then: how do we handle cases where a user is just typing at the end of the text (or within a single paragraph) while the rest of the document isn’t any different?

Are there ways to basically say “from 0 - 1000 we can reuse, then update just the rest”? We already have a fast lookup of things, but some users still report performance issues in edge cases (or when there’s too much to go over, like 50k word documents).

thanks in advance!

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [December 14, 2024, 6:45pm UTC](https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044/2 "2024-12-14T18:45:42Z")

</div>

> [@spaceemotion](#):
>
> Are there ways to basically say “from 0 - 1000 we can reuse, then update just the rest”?

Yes, you can do this with [`RangeSet.update`](https://codemirror.net/docs/ref/#state.RangeSet.update). Determine which area you want to redraw, pass that range as `filterFrom`/`filterTo` with a filter that always returns false, and pass the newly drawn decorations in `add`. (You’ll want to make sure you map the set before updating, so that its positions actually correspond to the post-change document.)

---

<div class="post-metadata">

### Author: ![spaceemotion](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/spaceemotion/32/4178_2.png) [@spaceemotion](https://discuss.prosemirror.net/u/spaceemotion)
#### Post date: [December 14, 2024, 9:07pm UTC](https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044/3 "2024-12-14T21:07:39Z")

</div>

Okay, cool! I am guessing that I can get the “affected range” from the transaction steps? Because I technically don’t know what the user was doing, so having a way to know which parts to focus on would be good.

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [December 14, 2024, 9:37pm UTC](https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044/4 "2024-12-14T21:37:12Z")

</div>

I accidentally linked to the CodeMirror docs there. In ProseMirror, the methods are [`add`](https://prosemirror.net/docs/ref/#view.DecorationSet.add) and [`remove`](https://prosemirror.net/docs/ref/#view.DecorationSet.remove).

You can inspect a transactions [step maps](https://prosemirror.net/docs/ref/#transform.Mapping) under `tr.mapping`, and compute the changed range from those.

---

<div class="post-metadata">

### Author: ![TeemuKoivisto](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/teemukoivisto/32/1185_2.png) [@TeemuKoivisto](https://discuss.prosemirror.net/u/TeemuKoivisto)
#### Post date: [December 18, 2024, 3:34pm UTC](https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044/5 "2024-12-18T15:34:29Z")

</div>

I am using this

```auto
/**
 * Returns a range of the edited blocks
 * @param oldDoc
 * @param newDoc
 * @returns
 */
export function getEditedBlocksRange(
  oldDoc: PMNode,
  newDoc: PMNode,
  depth = 1
): [number, number] | undefined {
  const from = oldDoc.content.findDiffStart(newDoc.content)
  const to = oldDoc.content.findDiffEnd(newDoc.content)?.b
  if (from === null || to === undefined) return undefined
  let start = newDoc.resolve(from)
  if (start.depth === 0) {
    start = newDoc.resolve(Math.min(from + 1, newDoc.nodeSize - 2))
  }
  let end = newDoc.resolve(to)
  if (end.depth === 0) {
    end = newDoc.resolve(Math.max(to - 1, 0))
  }
  return [start.before(depth), end.after(depth)]
}

```

to get the range of edited block nodes to recompute everything within it.

---

<div class="post-metadata">

### Author: ![spaceemotion](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/spaceemotion/32/4178_2.png) [@spaceemotion](https://discuss.prosemirror.net/u/spaceemotion)
#### Post date: [December 18, 2024, 4:40pm UTC](https://discuss.prosemirror.net/t/any-tips-for-caching-improving-performance-of-decorations/8044/6 "2024-12-18T16:40:36Z")

</div>

I wonder what’s faster?

1. diffing the document (using the solution by @TeemuKoivisto above)
2. re-applying just all decorations, always (could be, depending on the code)
3. using the step maps as @marijn described above, and find out the range that way.
