0
Fork 0
mirror of https://github.com/fastmail/Squire.git synced 2024-12-22 15:23:29 -05:00

Memoize node category with weak map

Fix horrendous performance of isInline etc.
This commit is contained in:
Neil Jenkins 2016-11-15 11:07:15 +11:00
parent 5d24e3eb4d
commit f46dee1255
5 changed files with 78 additions and 24 deletions

View file

@ -47,6 +47,7 @@ var cantFocusEmptyTextNodes = isIElt11 || isWebKit;
var losesSelectionOnBlur = isIElt11; var losesSelectionOnBlur = isIElt11;
var canObserveMutations = typeof MutationObserver !== 'undefined'; var canObserveMutations = typeof MutationObserver !== 'undefined';
var canWeakMap = typeof WeakMap !== 'undefined';
// Use [^ \t\r\n] instead of \S so that nbsp does not count as white-space // Use [^ \t\r\n] instead of \S so that nbsp does not count as white-space
var notWS = /[^ \t\r\n]/; var notWS = /[^ \t\r\n]/;
@ -201,25 +202,48 @@ function every ( nodeList, fn ) {
// --- // ---
var UNKNOWN = 0;
var INLINE = 1;
var BLOCK = 2;
var CONTAINER = 3;
var nodeCategoryCache = canWeakMap ? new WeakMap() : null;
function isLeaf ( node ) { function isLeaf ( node ) {
return node.nodeType === ELEMENT_NODE && return node.nodeType === ELEMENT_NODE && !!leafNodeNames[ node.nodeName ];
!!leafNodeNames[ node.nodeName ];
} }
function isInline ( node ) { function getNodeCategory ( node ) {
return inlineNodeNames.test( node.nodeName ) && if ( canWeakMap && nodeCategoryCache.has( node ) ) {
return nodeCategoryCache.get( node );
}
var type = node.nodeType;
var nodeCategory;
if ( type === TEXT_NODE ) {
nodeCategory = INLINE;
} else if ( type !== ELEMENT_NODE && type !== DOCUMENT_FRAGMENT_NODE ) {
nodeCategory = UNKNOWN;
} else if ( !every( node.childNodes, isInline ) ) {
// Malformed HTML can have block tags inside inline tags. Need to treat // Malformed HTML can have block tags inside inline tags. Need to treat
// these as containers rather than inline. See #239. // these as containers rather than inline. See #239.
( node.nodeType === TEXT_NODE || every( node.childNodes, isInline ) ); nodeCategory = CONTAINER;
} else if ( inlineNodeNames.test( node.nodeName ) ) {
nodeCategory = INLINE;
} else {
nodeCategory = BLOCK;
}
if ( canWeakMap ) {
nodeCategoryCache.set( node, nodeCategory );
}
return nodeCategory;
}
function isInline ( node ) {
return getNodeCategory( node ) === INLINE;
} }
function isBlock ( node ) { function isBlock ( node ) {
var type = node.nodeType; return getNodeCategory( node ) === BLOCK;
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
!isInline( node ) && every( node.childNodes, isInline );
} }
function isContainer ( node ) { function isContainer ( node ) {
var type = node.nodeType; return getNodeCategory( node ) === CONTAINER;
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
!isInline( node ) && !isBlock( node );
} }
function getBlockWalker ( node, root ) { function getBlockWalker ( node, root ) {
@ -3110,6 +3134,9 @@ proto._keyUpDetectChange = function ( event ) {
}; };
proto._docWasChanged = function () { proto._docWasChanged = function () {
if ( canWeakMap ) {
nodeCategoryCache = new WeakMap();
}
if ( this._ignoreAllChanges ) { if ( this._ignoreAllChanges ) {
return; return;
} }

File diff suppressed because one or more lines are too long

View file

@ -43,6 +43,7 @@ var cantFocusEmptyTextNodes = isIElt11 || isWebKit;
var losesSelectionOnBlur = isIElt11; var losesSelectionOnBlur = isIElt11;
var canObserveMutations = typeof MutationObserver !== 'undefined'; var canObserveMutations = typeof MutationObserver !== 'undefined';
var canWeakMap = typeof WeakMap !== 'undefined';
// Use [^ \t\r\n] instead of \S so that nbsp does not count as white-space // Use [^ \t\r\n] instead of \S so that nbsp does not count as white-space
var notWS = /[^ \t\r\n]/; var notWS = /[^ \t\r\n]/;

View file

@ -746,6 +746,9 @@ proto._keyUpDetectChange = function ( event ) {
}; };
proto._docWasChanged = function () { proto._docWasChanged = function () {
if ( canWeakMap ) {
nodeCategoryCache = new WeakMap();
}
if ( this._ignoreAllChanges ) { if ( this._ignoreAllChanges ) {
return; return;
} }

View file

@ -22,25 +22,48 @@ function every ( nodeList, fn ) {
// --- // ---
var UNKNOWN = 0;
var INLINE = 1;
var BLOCK = 2;
var CONTAINER = 3;
var nodeCategoryCache = canWeakMap ? new WeakMap() : null;
function isLeaf ( node ) { function isLeaf ( node ) {
return node.nodeType === ELEMENT_NODE && return node.nodeType === ELEMENT_NODE && !!leafNodeNames[ node.nodeName ];
!!leafNodeNames[ node.nodeName ];
} }
function isInline ( node ) { function getNodeCategory ( node ) {
return inlineNodeNames.test( node.nodeName ) && if ( canWeakMap && nodeCategoryCache.has( node ) ) {
return nodeCategoryCache.get( node );
}
var type = node.nodeType;
var nodeCategory;
if ( type === TEXT_NODE ) {
nodeCategory = INLINE;
} else if ( type !== ELEMENT_NODE && type !== DOCUMENT_FRAGMENT_NODE ) {
nodeCategory = UNKNOWN;
} else if ( !every( node.childNodes, isInline ) ) {
// Malformed HTML can have block tags inside inline tags. Need to treat // Malformed HTML can have block tags inside inline tags. Need to treat
// these as containers rather than inline. See #239. // these as containers rather than inline. See #239.
( node.nodeType === TEXT_NODE || every( node.childNodes, isInline ) ); nodeCategory = CONTAINER;
} else if ( inlineNodeNames.test( node.nodeName ) ) {
nodeCategory = INLINE;
} else {
nodeCategory = BLOCK;
}
if ( canWeakMap ) {
nodeCategoryCache.set( node, nodeCategory );
}
return nodeCategory;
}
function isInline ( node ) {
return getNodeCategory( node ) === INLINE;
} }
function isBlock ( node ) { function isBlock ( node ) {
var type = node.nodeType; return getNodeCategory( node ) === BLOCK;
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
!isInline( node ) && every( node.childNodes, isInline );
} }
function isContainer ( node ) { function isContainer ( node ) {
var type = node.nodeType; return getNodeCategory( node ) === CONTAINER;
return ( type === ELEMENT_NODE || type === DOCUMENT_FRAGMENT_NODE ) &&
!isInline( node ) && !isBlock( node );
} }
function getBlockWalker ( node, root ) { function getBlockWalker ( node, root ) {