i use tableEditing
in table node, its slow when i select the cell in large document|
this is in large document
i use tableEditing
in table node, its slow when i select the cell in large document|
this is in large document
I noticed this as well and have a patch for this which speeds up compute time greatly for large table nodes. It essentially debounces a particular handler for column resizing which is triggered a lot when user interacts with table (mouse over)
I will try to open a pull request soon and maybe it will help you but let me know if you are using column resizing or not.
There might be limitations to my implementation so I am curious what the other authors think.
Again, this just targets the mousemove handler which fires too often for larger table nodes (if you used column resizing). If you want to copy this in to your node_modules you can give it a try quickly.
Edit: Opened a PR - Improve performance of column resizing mousemouse handler by debouncing by bZichett Ā· Pull Request #154 Ā· ProseMirror/prosemirror-tables Ā· GitHub
Yea, I used column resizing, but itās still slow after the column resizing is disabled.
Iād love to help you out still .
See if you can find where in the plugin most computation time is happening and weāll see if we can work on some improvements. Let me know if you havenāt used a javascript profiler yet though as I donāt know your experience.
I started with column resizing only because it decimated performance with that one handler for large tables (but the PR is just reducing transaction on mouse events not table selections which require expensive ones that might be throttled as well in a similar manner).
There are likely a few more hot code paths that could be optimized beyond this as well.
I found the reason, when the tableEditing
create the selectedCell decorations,it will enter to iterDeco
function. the iterDeco function speed up compute time greatly. when it forChild, the condition result == empty
is not true, even though the result is empty, but they are not the same variable, which will cause foreachall nodes of document(large document will speed up compute time greatly)
DecorationGroup.prototype.forChild = function forChild (offset, child) {
if (child.isLeaf) { return DecorationSet.empty }
var found = [];
for (var i = 0; i < this.members.length; i++) {
var result = this.members[i].forChild(offset, child);
if (result == empty) { continue }
if (result instanceof DecorationGroup) { found = found.concat(result.members); }
else { found.push(result); }
}
return DecorationGroup.from(found)
}
So, I copy the tableEditing code from prosemirror-tables
into my project. then itās solved. Iām not sure this is a bug of prosemirror-view
?
the following is a part of tableEditing code
export function tableEditing({ allowTableNodeSelection = false } = {}) {
return new Plugin({
key: tableEditingKey,
state: {
init() {
return null;
},
apply(tr, cur) {
let set = tr.getMeta(tableEditingKey);
if (set != null) return set == -1 ? null : set;
if (cur == null || !tr.docChanged) return cur;
let { deleted, pos } = tr.mapping.mapResult(cur);
return deleted ? null : pos;
},
},
props: {
decorations: drawCellSelection,
handleDOMEvents: {
mousedown: handleMouseDown,
},
createSelectionBetween(view) {
if (tableEditingKey.getState(view.state) != null)
return view.state.selection;
},
handleTripleClick,
handleKeyDown,
handlePaste,
},
appendTransaction(_, oldState, state) {
return normalizeSelection(
state,
fixTables(state, oldState),
allowTableNodeSelection,
);
},
});
}
export function drawCellSelection(state) {
if (!(state.selection instanceof CellSelection)) return null;
let cells = [];
state.selection.forEachCell((node, pos) => {
cells.push(
Decoration.node(pos, pos + node.nodeSize, { class: 'selectedCell' }),
);
});
return DecorationSet.create(state.doc, cells);
}
Ah I see. There is another handler that cannot keep up with large tables atm so for the time being, Iād like to test this approach which I just finished up now. It throttles the mousemove during cell selection changes. Again a little hit to the UX but required at the moment for a functional user experience.
Copy over the two core files to test it out (only two files that changed that you need to swap into node_modules, the rest are tests and demo updates)
Testing a public exposed npm module here: @projectample/prosemirror-tables
If you are using webpack, alias works well
'prosemirror-tables': '@projectample/prosemirror-tables',
Its better but still not quite there. Still investigating but feel free to try that out. Seeming more like a memory leak in tableEditing
, since the first interaction for dragging works well but then the next one slows down. This also happens when there are multiple tables in the same document of medium / small size (dozens)
How do I know this: I disabled all the decorations and plugins of the EditorView (except tableEditing
) and the performance was OK but only for the first few interactions (anything, including drags) but then it still degraded completely to the same as before. So its likely not caused by decorations but exacerbated severely if there are a lot of them.
@jiaxiaxia Check a browser different than Chrome (or let me know what browser you are using)
Might be related to DOMObserver
usage. It appears that Chromes javascript profiler is obfuscating whatever is long running.
Ok, finally reporting something interesting; the text in the table I was working with had spelling corrections pending, and it appears Google chromes implementation has to refire on every interaction.
I am aware of some threads about spellcheck but I was not aware of the performance ramifications being this deep. Is is possible your table is filled with non-English characters that your browser is attempting to correct as well?
Performance stabilized by adding the spellcheck=false attribute to just the
element.@marijn Thoughts on this? I reached out to a prosemirror-table author and he said he wasnt working on it anymore; Been trying to improve performance there (2 open PRās) but this spell check one might be heavily effecting non english Chrome browser users more than anything. Im not sure if its related to prosemirror-tables
and its DOMObserver
usage or a core prosemirror library
Edit: I see this comment now - What is the current state of spellcheck? - #11 by marijn
I am not planning to maintain prosemirror-tables either. Itād be great if a new maintainer can be found, but itās not going to be me.
Iām not sure what you mean by DOMObserver usage and how that is related to this. Turning spell-checking off is an option sites have, but not something I want to make the library do by default.
Well, one thing I know for sure is that a large table filled with German language that triggers chromes spell check causes massive performance issues. Its exacerbated by tables due to the more complex DOM structure, presuming.
There is definitely more room for figuring out some performance issues with prosemirror-tables though. Iāll be looking into this more.
As for the spellcheck attribute. I added a conditional attribute prop for when a large doc is received by editor state (sufficiently large > 10,000 to start.) Its fine not to have built in to prosemirror.
I used the chrome 95.0.4638.69,I didnāt used webpack, I used vite
@jiaxiaxia Does your document have a lot of text that is triggering chromes auto spell checker? (Or just an empty table cells?)
If itās empty table cells, the debounce and throttle in the pull requests I have for prosemirror-tables should help a lot.
Yeaļ¼it did help a lot, but it is not the main reason for me. my main proplem is Why selectedCell decoration so slow in large document - #5 by bZichett
I donāt knowāI couldnāt make much of the iterDeco
comments you made.
the third parameter of the onNode
function will call deco.forChild. when forChild, the result
is empty$4, but the empty is empty$1 after build ,so they are different.
Could it be that youāre loading multiple versions of prosemirror-view?