PERF: faster length calculation of composer body

Every time we type a letter the composer issues a reply length check.

This is due to the interconnecting components, the title one depends on the
body which means that this decision making is passed along each time, even
if the title does not need it strictly.

Anyway...

This optimisation has 3 parts:

1. If the composer string is super long (10000 chars) we will bypass, quote
stripping and space squashing.

2. Quote stripping is now done much more efficiently, we strip them all in
one go

3. Space squashing eg: `hello    world` to `hello world` is done in an
efficient loop to avoid needing to generate superflous strings that need
GC
This commit is contained in:
Sam Saffron 2019-08-22 11:56:22 +10:00
parent 2d5b928da9
commit afc7830be5

View File

@ -56,7 +56,8 @@ const CLOSED = "closed",
categoryId: "topic.category.id",
tags: "topic.tags",
featuredLink: "topic.featured_link"
};
},
FAST_REPLY_LENGTH_THRESHOLD = 10000;
export const SAVE_LABELS = {
[EDIT]: "composer.save_edit",
@ -445,10 +446,62 @@ const Composer = RestModel.extend({
@computed("reply")
replyLength(reply) {
reply = reply || "";
while (Quote.REGEXP.test(reply)) {
reply = reply.replace(Quote.REGEXP, "");
if (reply.length > FAST_REPLY_LENGTH_THRESHOLD) {
return reply.length;
}
return reply.replace(/\s+/gim, " ").trim().length;
if (Quote.REGEXP.test(reply)) {
// make it global so we can strip all quotes at once
const regex = new RegExp(Quote.REGEXP.source, "img");
reply = reply.replace(regex, "");
}
// This is in place so we do not generate any intermediate
// strings while calculating the length, this is issued
// every keypress in the composer so it needs to be very fast
let len = 0,
skipSpace = true;
for (let i = 0; i < reply.length; i++) {
const code = reply.charCodeAt(i);
let isSpace = false;
if (code >= 0x2000 && code <= 0x200a) {
isSpace = true;
} else {
switch (code) {
case 0x09: // \t
case 0x0a: // \n
case 0x0b: // \v
case 0x0c: // \f
case 0x0d: // \r
case 0x20:
case 0xa0:
case 0x1680:
case 0x202f:
case 0x205f:
case 0x3000:
isSpace = true;
}
}
if (isSpace) {
if (!skipSpace) {
len++;
skipSpace = true;
}
} else {
len++;
skipSpace = false;
}
}
if (len > 0 && skipSpace) {
len--;
}
return len;
},
@on("init")