Skip to content

Commit 185d4b5

Browse files
committed
Performance: improve .trim performance for large strings contains lots of whitespaces
The old implementation took O(N^2) time to trim the string when multiple adjacent spaces were present. For instance, consider the string "A B" (10 spaces between A and B). Then old regexp /[\s]+$/ would take 10 steps until it realizes the regexp does not match at position 1. Then it would try to match the regexp at position 2, and it would take 9 steps. Then 8 steps for position 3, ... so it would take 10*10/2 steps until it figures out the regexp does not match. The new approach is to require "non-whitespace" char before the whitespace run, so it spends just one step for each space in the string.
1 parent 8d9efb6 commit 185d4b5

File tree

1 file changed

+26
-7
lines changed

1 file changed

+26
-7
lines changed

src/jquery/core.js

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ var findProp,
1717

1818
// Support: Android <=4.0 only
1919
// Make sure we trim BOM and NBSP
20-
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
20+
ltrim = /^[\s\uFEFF\xA0]+/,
21+
// Require that the "whitespace run" starts from a non-whitespace
22+
// to avoid O(N^2) behavior when the engine would try matching "\s$" at each space position.
23+
// It is important that non-whitespace char is mandatory for regexp performance reasons,
24+
// however, it does not break correctness since whitespace-only string will be trimmed by ltrim above.
25+
rtrim = /([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/;
2126

2227
migratePatchFunc( jQuery.fn, "init", function( arg1 ) {
2328
var args = Array.prototype.slice.call( arguments );
@@ -106,12 +111,26 @@ migrateWarnProp( jQuery.expr, ":", jQuery.expr.pseudos, "expr-pre-pseudos",
106111

107112
// Prior to jQuery 3.1.1 there were internal refs so we don't warn there
108113
if ( jQueryVersionSince( "3.1.1" ) ) {
109-
migratePatchAndWarnFunc( jQuery, "trim", function( text ) {
110-
return text == null ?
111-
"" :
112-
( text + "" ).replace( rtrim, "" );
113-
}, "trim",
114-
"jQuery.trim is deprecated; use String.prototype.trim" );
114+
var useDefaultTrim = false;
115+
if (String.prototype.trim) {
116+
useDefaultTrim = "_" === " \uFEFF\xA0_\uFEFF\xA0 ".trim();
117+
}
118+
119+
if (useDefaultTrim) {
120+
migratePatchAndWarnFunc( jQuery, "trim", function( text ) {
121+
return text == null ?
122+
"" :
123+
( text + "" ).trim();
124+
}, "trim",
125+
"jQuery.trim is deprecated; use String.prototype.trim" );
126+
} else {
127+
migratePatchAndWarnFunc( jQuery, "trim", function( text ) {
128+
return text == null ?
129+
"" :
130+
( text + "" ).replace( ltrim, "" ).replace( rtrim, "$1" );
131+
}, "trim",
132+
"jQuery.trim is deprecated; use String.prototype.trim" );
133+
}
115134
}
116135

117136
// Prior to jQuery 3.2 there were internal refs so we don't warn there

0 commit comments

Comments
 (0)