mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
perf(site): use lazy iteration in sliceAtGraphemeBoundary (#23671)
Array.from(graphemeSegmenter.segment(text)) materializes the entire text into an array before iterating, even though the loop breaks early at the visible prefix length. During streaming at 60fps, this makes each frame O(full text) instead of O(prefix). Benchmark on 5000-char text with 200-char prefix: 22.6x faster (1.44ms to 0.06ms per call, saving 8.3% of the frame budget). The fallback codepoint path had the same issue with Array.from.
This commit is contained in:
@@ -327,9 +327,12 @@ function sliceAtGraphemeBoundary(
|
||||
|
||||
if (graphemeSegmenter) {
|
||||
let safeEnd = 0;
|
||||
const segments = Array.from(graphemeSegmenter.segment(text));
|
||||
|
||||
for (const segment of segments) {
|
||||
// Iterate the segmenter lazily instead of materializing
|
||||
// with Array.from(). The early break makes this O(prefix)
|
||||
// instead of O(full text), which matters at 60fps during
|
||||
// streaming where the visible prefix is much shorter than
|
||||
// the full accumulated text.
|
||||
for (const segment of graphemeSegmenter.segment(text)) {
|
||||
const segmentEnd = segment.index + segment.segment.length;
|
||||
if (segmentEnd > maxCodeUnitLength) {
|
||||
break;
|
||||
@@ -342,9 +345,10 @@ function sliceAtGraphemeBoundary(
|
||||
|
||||
// Fallback: iterate by codepoint to avoid splitting surrogate
|
||||
// pairs. This is less precise than grapheme segmentation but
|
||||
// still safe for rendering.
|
||||
// still safe for rendering. Iterating the string directly with
|
||||
// for...of is lazy and avoids the O(n) Array.from() cost.
|
||||
let safeEnd = 0;
|
||||
for (const codePoint of Array.from(text)) {
|
||||
for (const codePoint of text) {
|
||||
const codePointEnd = safeEnd + codePoint.length;
|
||||
if (codePointEnd > maxCodeUnitLength) {
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user