Improve performance when rendering many emoji
This commit is contained in:
parent
6f242eca57
commit
7f50fcdb54
3 changed files with 32 additions and 17 deletions
|
@ -96,3 +96,19 @@ story.add('Custom Text Render', () => {
|
||||||
|
|
||||||
return <Emojify {...props} />;
|
return <Emojify {...props} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
story.add('Tens of thousands of emoji', () => {
|
||||||
|
const props = createProps({
|
||||||
|
text: '💅'.repeat(40000),
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Emojify {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Tens of thousands of emoji, interspersed with text', () => {
|
||||||
|
const props = createProps({
|
||||||
|
text: '💅 hi '.repeat(40000),
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Emojify {...props} />;
|
||||||
|
});
|
||||||
|
|
|
@ -28,25 +28,15 @@ describe('emoji', () => {
|
||||||
{ type: 'emoji', value: '😛' },
|
{ type: 'emoji', value: '😛' },
|
||||||
{ type: 'text', value: 'world' },
|
{ type: 'text', value: 'world' },
|
||||||
{ type: 'emoji', value: '😎' },
|
{ type: 'emoji', value: '😎' },
|
||||||
{ type: 'text', value: '' },
|
|
||||||
{ type: 'emoji', value: '😛' },
|
{ type: 'emoji', value: '😛' },
|
||||||
{ type: 'text', value: '!' },
|
{ type: 'text', value: '!' },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty string after split at the end', () => {
|
it('returns emojis as text after 5,000 emojis are found', () => {
|
||||||
assert.deepStrictEqual(splitByEmoji('hello😛'), [
|
assert.deepStrictEqual(splitByEmoji('💬'.repeat(5002)), [
|
||||||
{ type: 'text', value: 'hello' },
|
...Array(5000).fill({ type: 'emoji', value: '💬' }),
|
||||||
{ type: 'emoji', value: '😛' },
|
{ type: 'text', value: '💬💬' },
|
||||||
{ type: 'text', value: '' },
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return empty string before the split at the start', () => {
|
|
||||||
assert.deepStrictEqual(splitByEmoji('😛hello'), [
|
|
||||||
{ type: 'text', value: '' },
|
|
||||||
{ type: 'emoji', value: '😛' },
|
|
||||||
{ type: 'text', value: 'hello' },
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
import emojiRegex from 'emoji-regex/es2015/RGI_Emoji';
|
import emojiRegex from 'emoji-regex/es2015/RGI_Emoji';
|
||||||
|
|
||||||
import { assert } from './assert';
|
import { assert } from './assert';
|
||||||
|
import { take } from './iterables';
|
||||||
|
|
||||||
const REGEXP = emojiRegex();
|
const REGEXP = emojiRegex();
|
||||||
|
const MAX_EMOJI_TO_MATCH = 5000;
|
||||||
|
|
||||||
export function replaceEmojiWithSpaces(value: string): string {
|
export function replaceEmojiWithSpaces(value: string): string {
|
||||||
return value.replace(REGEXP, ' ');
|
return value.replace(REGEXP, ' ');
|
||||||
|
@ -17,19 +19,26 @@ export type SplitElement = Readonly<{
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export function splitByEmoji(value: string): ReadonlyArray<SplitElement> {
|
export function splitByEmoji(value: string): ReadonlyArray<SplitElement> {
|
||||||
const emojis = value.matchAll(REGEXP);
|
const emojis = take(value.matchAll(REGEXP), MAX_EMOJI_TO_MATCH);
|
||||||
|
|
||||||
const result: Array<SplitElement> = [];
|
const result: Array<SplitElement> = [];
|
||||||
let lastIndex = 0;
|
let lastIndex = 0;
|
||||||
for (const match of emojis) {
|
for (const match of emojis) {
|
||||||
result.push({ type: 'text', value: value.slice(lastIndex, match.index) });
|
const nonEmojiText = value.slice(lastIndex, match.index);
|
||||||
|
if (nonEmojiText) {
|
||||||
|
result.push({ type: 'text', value: nonEmojiText });
|
||||||
|
}
|
||||||
|
|
||||||
result.push({ type: 'emoji', value: match[0] });
|
result.push({ type: 'emoji', value: match[0] });
|
||||||
|
|
||||||
assert(match.index !== undefined, '`matchAll` should provide indices');
|
assert(match.index !== undefined, '`matchAll` should provide indices');
|
||||||
lastIndex = match.index + match[0].length;
|
lastIndex = match.index + match[0].length;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push({ type: 'text', value: value.slice(lastIndex) });
|
const finalNonEmojiText = value.slice(lastIndex);
|
||||||
|
if (finalNonEmojiText) {
|
||||||
|
result.push({ type: 'text', value: finalNonEmojiText });
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue