1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-04-21 13:51:59 +02:00

Avoid transforming dirty paths if the op won't touch them ()

* Avoid transforming dirty paths if the op won't touch them

* Avoid the loop entirely if op doesn't affect path
This commit is contained in:
Steve Marquis 2021-12-18 07:39:09 -08:00 committed by GitHub
parent ccafb6982f
commit e5427dddfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 12 deletions
.changeset
packages/slate/src

@ -0,0 +1,5 @@
---
'slate': patch
---
Optimize path transforms during normalization

@ -13,7 +13,7 @@ import {
Text,
Transforms,
} from './'
import { DIRTY_PATHS, FLUSHING } from './utils/weak-maps'
import { DIRTY_PATHS, DIRTY_PATH_KEYS, FLUSHING } from './utils/weak-maps'
/**
* Create a new Slate `Editor` object.
@ -42,33 +42,41 @@ export const createEditor = (): Editor => {
RangeRef.transform(ref, op)
}
const set = new Set()
const dirtyPaths: Path[] = []
const oldDirtyPaths = DIRTY_PATHS.get(editor) || []
const oldDirtyPathKeys = DIRTY_PATH_KEYS.get(editor) || new Set()
let dirtyPaths: Path[]
let dirtyPathKeys: Set<string>
const add = (path: Path | null) => {
if (path) {
const key = path.join(',')
if (!set.has(key)) {
set.add(key)
if (!dirtyPathKeys.has(key)) {
dirtyPathKeys.add(key)
dirtyPaths.push(path)
}
}
}
const oldDirtyPaths = DIRTY_PATHS.get(editor) || []
const newDirtyPaths = getDirtyPaths(op)
for (const path of oldDirtyPaths) {
const newPath = Path.transform(path, op)
add(newPath)
if (Path.operationCanTransformPath(op)) {
dirtyPaths = []
dirtyPathKeys = new Set()
for (const path of oldDirtyPaths) {
const newPath = Path.transform(path, op)
add(newPath)
}
} else {
dirtyPaths = oldDirtyPaths
dirtyPathKeys = oldDirtyPathKeys
}
const newDirtyPaths = getDirtyPaths(op)
for (const path of newDirtyPaths) {
add(path)
}
DIRTY_PATHS.set(editor, dirtyPaths)
DIRTY_PATH_KEYS.set(editor, dirtyPathKeys)
Transforms.transform(editor, op)
editor.operations.push(op)
Editor.normalize(editor)

@ -19,6 +19,7 @@ import {
} from '..'
import {
DIRTY_PATHS,
DIRTY_PATH_KEYS,
NORMALIZING,
PATH_REFS,
POINT_REFS,
@ -979,13 +980,26 @@ export const Editor: EditorInterface = {
return DIRTY_PATHS.get(editor) || []
}
const getDirtyPathKeys = (editor: Editor) => {
return DIRTY_PATH_KEYS.get(editor) || new Set()
}
const popDirtyPath = (editor: Editor): Path => {
const path = getDirtyPaths(editor).pop()!
const key = path.join(',')
getDirtyPathKeys(editor).delete(key)
return path
}
if (!Editor.isNormalizing(editor)) {
return
}
if (force) {
const allPaths = Array.from(Node.nodes(editor), ([, p]) => p)
const allPathKeys = new Set(allPaths.map(p => p.join(',')))
DIRTY_PATHS.set(editor, allPaths)
DIRTY_PATH_KEYS.set(editor, allPathKeys)
}
if (getDirtyPaths(editor).length === 0) {
@ -1026,7 +1040,7 @@ export const Editor: EditorInterface = {
`)
}
const dirtyPath = getDirtyPaths(editor).pop()!
const dirtyPath = popDirtyPath(editor)
// If the node doesn't exist in the tree, it does not need to be normalized.
if (Node.has(editor, dirtyPath)) {

@ -34,6 +34,7 @@ export interface PathInterface {
}
) => Path[]
next: (path: Path) => Path
operationCanTransformPath: (operation: Operation) => boolean
parent: (path: Path) => Path
previous: (path: Path) => Path
relative: (path: Path, ancestor: Path) => Path
@ -291,6 +292,26 @@ export const Path: PathInterface = {
return path.slice(0, -1).concat(last + 1)
},
/**
* Returns whether this operation can affect paths or not. Used as an
* optimization when updating dirty paths during normalization
*
* NOTE: This *must* be kept in sync with the implementation of 'transform'
* below
*/
operationCanTransformPath(operation: Operation): boolean {
switch (operation.type) {
case 'insert_node':
case 'remove_node':
case 'merge_node':
case 'split_node':
case 'move_node':
return true
default:
return false
}
},
/**
* Given a path, return a new path referring to the parent node above it.
*/

@ -1,6 +1,7 @@
import { Editor, Path, PathRef, PointRef, RangeRef } from '..'
export const DIRTY_PATHS: WeakMap<Editor, Path[]> = new WeakMap()
export const DIRTY_PATH_KEYS: WeakMap<Editor, Set<string>> = new WeakMap()
export const FLUSHING: WeakMap<Editor, boolean> = new WeakMap()
export const NORMALIZING: WeakMap<Editor, boolean> = new WeakMap()
export const PATH_REFS: WeakMap<Editor, Set<PathRef>> = new WeakMap()