1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-30 18:39:51 +02:00

Perhaps faster normalization: Never visit a descendant twice in normalizaton (#1661)

* Perhaps faster normalization: Never visit a descendant twice in normalizaton

* Change getFirstInvalidaDescendantKey to getFirstInvalidaDescendant

* Add from-JSON-big in benchmark

* Better annotation

* Remove un-used test change
This commit is contained in:
Jinxuan Zhu
2018-03-21 18:36:25 -04:00
committed by Ian Storm Taylor
parent 6ad3aada5b
commit c569569729
4 changed files with 102 additions and 22 deletions

View File

@@ -0,0 +1,66 @@
/* eslint-disable react/jsx-key */
import { Value } from '../..'
export default function(json) {
Value.fromJSON(json)
}
export const input = {
document: {
nodes: Array.from(Array(100)).map(() => ({
type: 'list',
object: 'block',
isVoid: false,
data: {},
nodes: Array.from(Array(10)).map(() => ({
type: 'list-item',
object: 'block',
isVoid: false,
data: {},
nodes: [
{
leaves: [
{
object: 'leaf',
marks: [],
text: '',
},
],
object: 'text',
},
{
type: 'link',
object: 'inline',
isVoid: false,
data: {
id: 1,
},
nodes: [
{
leaves: [
{
object: 'leaf',
marks: [],
text: 'Some text for a link',
},
],
object: 'text',
},
],
},
{
leaves: [
{
object: 'leaf',
marks: [],
text: '',
},
],
object: 'text',
},
],
})),
})),
},
}

View File

@@ -65,32 +65,17 @@ function normalizeNodeAndChildren(change, node, schema) {
return
}
const normalizedKeys = []
let child = node.nodes.first()
let child = node.getFirstInvalidDescendant(schema)
let path = change.value.document.getPath(node.key)
// We can't just loop the children and normalize them, because in the process
// of normalizing one child, we might end up creating another. Instead, we
// have to normalize one at a time, and check for new children along the way.
while (node && child) {
const lastSize = change.operations.size
normalizeNodeAndChildren(change, child, schema)
normalizedKeys.push(child.key)
// PERF: if size is unchanged, then no operation happens
// Therefore we can simply normalize the next child
if (lastSize === change.operations.size) {
const nextIndex = node.nodes.indexOf(child) + 1
child = node.nodes.get(nextIndex)
} else {
node = change.value.document.refindNode(path, node.key)
if (!node) {
path = []
child = null
} else {
path = change.value.document.refindPath(path, node.key)
child = node.nodes.find(c => !normalizedKeys.includes(c.key))
}
child = node.getFirstInvalidDescendant(schema)
}
}

View File

@@ -1987,6 +1987,22 @@ class Node {
validate(schema) {
return schema.validateNode(this)
}
/**
* Get the first invalid descendant
*
* @param {Schema} schema
* @return {Node|Text|Null}
*/
getFirstInvalidDescendant(schema) {
let result = null
this.nodes.find(n => {
result = n.validate(schema) ? n : n.getFirstInvalidDescendant(schema)
return result
})
return result
}
}
/**
@@ -2072,6 +2088,7 @@ memoize(
'getTextAtOffset',
'getTextsAtRangeAsArray',
'validate',
'getFirstInvalidDescendant',
],
{
takesArguments: true,

View File

@@ -495,6 +495,18 @@ class Text extends Record(DEFAULTS) {
validate(schema) {
return schema.validateNode(this)
}
/**
* Get the first invalid descendant
* PREF: Do not cache this method; because it can cause cycle reference
*
* @param {Schema} schema
* @returns {Text|Null}
*/
getFirstInvalidDescendant(schema) {
return this.validate(schema) ? this : null
}
}
/**