quick-lint-js
quick-lint-js copied to clipboard
27$: Web demo is slow (Firefox macOS)
Parsing jQuery on my MacBook Pro:
- Web demo in Firefox: ~95 ms per parse
- -O0 CLI build: ~70 ms per parse
- -O2 CLI build: ~14 ms per parse
Surely the web demo shouldn't be 1/6th the speed. Right?
- [ ] Precisely measure parse time in web demo
- [ ] Audit web demo build flags
- [ ] ~~Measure parse time in VS Code (which also uses WebAssembly)~~
- [ ] Compare with Chromium and Safari
On top of parsing being slow, layout is slow (~53 ms) even for small changes (single character additions within a line).
On this program, linting 12 times took 1115.6 milliseconds in Edge on my 5950X on Linux. 382.2 milliseconds were in wasm. 468.8 milliseconds were in "Layout".
john_hillington_ reported slowness on his machine (~184 milliseconds per lint).
Each change, the demo currently creates one giant text node, then splits it up. This is expensive.
Ideally, we'd reuse text nodes from the previous run. Short of that, we can generate the little text nodes from the start rather than splitting.
Another approach is querying the location of the marks using Range#getClientRects. This prototype seems to roughly work:
let range = window.document.createRange();
range.setStart(editor.childNodes[0], 50);
range.setEnd(editor.childNodes[0], 53);
let rects = range.getClientRects();
console.log(rects);
for (let r of rects) {
let s = document.createElement('span');
s.style.position = 'absolute';
s.style.top = `${r.top}px`;
s.style.left = `${r.left}px`;
s.style.width = `${r.width}px`;
s.style.height = `${r.height}px`;
s.style.backgroundColor = 'rgba(255, 0, 255, 0.5)';
document.body.appendChild(s);
}
In Edge, getClientRects is relatively slow (~2 ms per call; 15 ms on a jQuery example with a few marks). Synchronizing the shadow code input is the real beast though (40+ ms per update). But even updating the textarea alone is slow (16 ms per update).
Splitting text nodes seems to be fast in Edge, but I didn't profile too carefully.
Perhaps we could try contenteditable.
In Edge, contenteditable is just as slow.
In Edge, with JS disabled, typing one character into a textarea containing jQuery takes about 77 ms according to Edge's profiler (17 ms layout, 14 ms update tree). Typing one character into a contenteditable div with a monospace font takes the same amount of time.
I tried Monaco Editor. I am impressed. Typing a character in jQuery takes 26 ms! However, decorations are deferred and take 40+1+9+1+10=61 ms. Disabling syntax highlighting and other features might speed up the decoration process.
I tried a stripped-down Monaco Editor instance. Typing a character in jQuery took 2+10+2+1 = 15 ms.
Config in the playground:
monaco.editor.create(document.getElementById('container'), {
value: '',
lineNumbers: false,
unusualLineTerminators: 'off',
lineDecorationsWidth: 0,
roundedSelection: false,
renderValidationDecorations: 'off', // ???
minimap: {
enabled: false
},
stopRenderingLineAfter: -1,
hover: {
enabled: false // @@@
},
links: false,
colorDecorators: false,
contextmenu: false,
inlineSuggest: {
enabled: false,
},
quickSuggestions: false,
padding: {
top: 0,
bottom: 0,
},
parameterHints: {
enabled: false,
},
autoIndent: 'brackets',
suggestOnTriggerCharacters: false,
acceptSuggestionOnEnter: 'off',
acceptSuggestionOnCommitCharacter: false,
snippetSuggestions: 'none',
copyWithSyntaxHighlighting: false,
tabCompletion: false,
selectionHighlight: false,
occurrencesHighlight: false,
codeLens: false,
lightbulb: {
enabled: false,
},
folding: false,
matchBrackets: 'never',
renderWhitespace: 'none',
renderLineHighlight: 'none',
showUnused: false,
showDeprecated: false,
inlayHints: {
enabled: false,
},
guides: {
bracketPairs: false,
bracketPairsHorizontal: false,
highlightActiveBracketPair: false,
indentation: false,
highlightActiveIndentation: false,
},
bracketPairColorization: {
enabled: false,
},
});
I pushed my position:absolute marks experiment to the refs/archive/web-demo-absolute-marking branch. I think moving forward we should use Monaco Editor instead of textarea.