From c39c8082a97dec8fc9ba64568d817ba87e348b48 Mon Sep 17 00:00:00 2001 From: Alex <32290337+ahoisl@users.noreply.github.com> Date: Tue, 12 Apr 2022 18:56:51 +0200 Subject: [PATCH] Fix pointRef leaks caused by not unref'ing (#4939) * Fix pointRef leaks caused by not unref'ing May cause severe performance degradation if more and more point refs need to be updated. * changeset --- .changeset/khaki-panthers-burn.md | 5 ++ packages/slate/src/transforms/node.ts | 122 +++++++++++++------------- packages/slate/src/transforms/text.ts | 6 +- 3 files changed, 71 insertions(+), 62 deletions(-) create mode 100644 .changeset/khaki-panthers-burn.md diff --git a/.changeset/khaki-panthers-burn.md b/.changeset/khaki-panthers-burn.md new file mode 100644 index 000000000..c6ad5b2df --- /dev/null +++ b/.changeset/khaki-panthers-burn.md @@ -0,0 +1,5 @@ +--- +'slate': patch +--- + +Fix pointRef leaks caused by not unref'ing diff --git a/packages/slate/src/transforms/node.ts b/packages/slate/src/transforms/node.ts index ba1c32834..11f3791dc 100644 --- a/packages/slate/src/transforms/node.ts +++ b/packages/slate/src/transforms/node.ts @@ -12,6 +12,7 @@ import { Ancestor, } from '..' import { NodeMatch, PropsCompare, PropsMerge } from '../interfaces/editor' +import { PointRef } from '../interfaces/point-ref' export interface NodeTransforms { insertNodes: ( @@ -728,82 +729,85 @@ export const NodeTransforms: NodeTransforms = { const beforeRef = Editor.pointRef(editor, at, { affinity: 'backward', }) - const [highest] = Editor.nodes(editor, { at, match, mode, voids }) + let afterRef: PointRef | undefined + try { + const [highest] = Editor.nodes(editor, { at, match, mode, voids }) - if (!highest) { - return - } + if (!highest) { + return + } - const voidMatch = Editor.void(editor, { at, mode: 'highest' }) - const nudge = 0 + const voidMatch = Editor.void(editor, { at, mode: 'highest' }) + const nudge = 0 - if (!voids && voidMatch) { - const [voidNode, voidPath] = voidMatch + if (!voids && voidMatch) { + const [voidNode, voidPath] = voidMatch - if (Element.isElement(voidNode) && editor.isInline(voidNode)) { - let after = Editor.after(editor, voidPath) + if (Element.isElement(voidNode) && editor.isInline(voidNode)) { + let after = Editor.after(editor, voidPath) - if (!after) { - const text = { text: '' } - const afterPath = Path.next(voidPath) - Transforms.insertNodes(editor, text, { at: afterPath, voids }) - after = Editor.point(editor, afterPath)! + if (!after) { + const text = { text: '' } + const afterPath = Path.next(voidPath) + Transforms.insertNodes(editor, text, { at: afterPath, voids }) + after = Editor.point(editor, afterPath)! + } + + at = after + always = true } - at = after + const siblingHeight = at.path.length - voidPath.length + height = siblingHeight + 1 always = true } - const siblingHeight = at.path.length - voidPath.length - height = siblingHeight + 1 - always = true - } + afterRef = Editor.pointRef(editor, at) + const depth = at.path.length - height + const [, highestPath] = highest + const lowestPath = at.path.slice(0, depth) + let position = height === 0 ? at.offset : at.path[depth] + nudge - const afterRef = Editor.pointRef(editor, at) - const depth = at.path.length - height - const [, highestPath] = highest - const lowestPath = at.path.slice(0, depth) - let position = height === 0 ? at.offset : at.path[depth] + nudge + for (const [node, path] of Editor.levels(editor, { + at: lowestPath, + reverse: true, + voids, + })) { + let split = false - for (const [node, path] of Editor.levels(editor, { - at: lowestPath, - reverse: true, - voids, - })) { - let split = false + if ( + path.length < highestPath.length || + path.length === 0 || + (!voids && Editor.isVoid(editor, node)) + ) { + break + } - if ( - path.length < highestPath.length || - path.length === 0 || - (!voids && Editor.isVoid(editor, node)) - ) { - break + const point = beforeRef.current! + const isEnd = Editor.isEnd(editor, point, path) + + if (always || !beforeRef || !Editor.isEdge(editor, point, path)) { + split = true + const properties = Node.extractProps(node) + editor.apply({ + type: 'split_node', + path, + position, + properties, + }) + } + + position = path[path.length - 1] + (split || isEnd ? 1 : 0) } - const point = beforeRef.current! - const isEnd = Editor.isEnd(editor, point, path) - - if (always || !beforeRef || !Editor.isEdge(editor, point, path)) { - split = true - const properties = Node.extractProps(node) - editor.apply({ - type: 'split_node', - path, - position, - properties, - }) + if (options.at == null) { + const point = afterRef.current || Editor.end(editor, []) + Transforms.select(editor, point) } - - position = path[path.length - 1] + (split || isEnd ? 1 : 0) + } finally { + beforeRef.unref() + afterRef?.unref() } - - if (options.at == null) { - const point = afterRef.current || Editor.end(editor, []) - Transforms.select(editor, point) - } - - beforeRef.unref() - afterRef.unref() }) }, diff --git a/packages/slate/src/transforms/text.ts b/packages/slate/src/transforms/text.ts index 4e587a437..51c9f6a0e 100644 --- a/packages/slate/src/transforms/text.ts +++ b/packages/slate/src/transforms/text.ts @@ -214,9 +214,9 @@ export const TextTransforms: TextTransforms = { }) } - const point = reverse - ? startRef.unref() || endRef.unref() - : endRef.unref() || startRef.unref() + const startUnref = startRef.unref() + const endUnref = endRef.unref() + const point = reverse ? startUnref || endUnref : endUnref || startUnref if (options.at == null && point) { Transforms.select(editor, point)