Skip to content

Commit

Permalink
perf: improve parsing by reducing math ops
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Sep 6, 2022
1 parent 5201c04 commit 0f4707d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 22 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ console.log(qs.stringify({ foo: ['bar', 'baz'] }))
╔═════════════════════════════════════════╤═════════╤═══════════════════╤═══════════╗
║ Slower tests │ Samples │ Result │ Tolerance ║
╟─────────────────────────────────────────┼─────────┼───────────────────┼───────────╢
║ qs │ 10000 │ 316071.64 op/sec │ ± 1.29 % ║
║ query-string │ 10000 334619.39 op/sec │ ± 1.43 % ║
║ querystringify │ 10000 │ 448353.77 op/sec │ ± 1.42 % ║
║ @aws-sdk/querystring-parser │ 1000 480685.11 op/sec │ ± 0.78 % ║
║ URLSearchParams-with-Object.fromEntries │ 10000 │ 833241.61 op/sec │ ± 2.97 % ║
║ URLSearchParams-with-construct │ 10000 │ 1184116.36 op/sec │ ± 4.50 % ║
║ node:querystring │ 3000 │ 1435004.35 op/sec │ ± 0.93 % ║
║ qs │ 10000 │ 314822.82 op/sec │ ± 1.12 % ║
║ query-string │ 1000 330364.46 op/sec │ ± 0.89 % ║
║ querystringify │ 10000 │ 442352.24 op/sec │ ± 1.31 % ║
║ @aws-sdk/querystring-parser │ 10000 471561.65 op/sec │ ± 1.12 % ║
║ URLSearchParams-with-Object.fromEntries │ 10000 │ 865453.19 op/sec │ ± 2.29 % ║
║ URLSearchParams-with-construct │ 10000 │ 1234031.63 op/sec │ ± 3.12 % ║
║ node:querystring │ 10000 │ 1484397.94 op/sec │ ± 2.46 % ║
╟─────────────────────────────────────────┼─────────┼───────────────────┼───────────╢
║ Fastest test │ Samples │ Result │ Tolerance ║
╟─────────────────────────────────────────┼─────────┼───────────────────┼───────────╢
║ fast-querystring │ 10000 │ 1706108.77 op/sec │ ± 4.66 % ║
║ fast-querystring │ 10000 │ 1798615.82 op/sec │ ± 2.65 % ║
╚═════════════════════════════════════════╧═════════╧═══════════════════╧═══════════╝
```

Expand Down
32 changes: 18 additions & 14 deletions lib/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,45 @@ function parse(input) {
let shouldDecodeValue = false;
let keyHasPlus = false;
let valueHasPlus = false;
let hasBothKeyValuePair = false;
let keyEndingIndex = 0;

// Have a boundary of input.length + 1 to access last pair inside the loop.
for (let i = 0; i < inputLength + 1; i++) {
let c = i !== inputLength ? input.charCodeAt(i) : -1;

// Handle '&' and end of line to pass the current values to result
if (c === 38 || c === -1) {
hasBothKeyValuePair = equalityIndex > startingIndex;
keyEndingIndex = hasBothKeyValuePair ? equalityIndex : i;

key = input.slice(startingIndex + 1, keyEndingIndex);

// Check if the current range consist of a single key
if (equalityIndex <= startingIndex) {
key = input.slice(startingIndex + 1, i);
value = "";
}
// Range consist of both key and value
else {
key = input.slice(startingIndex + 1, equalityIndex);
if (hasBothKeyValuePair) {
value = input.slice(equalityIndex + 1, i);
}

// Add key/value pair only if the range size is greater than 1; a.k.a. contains at least "="
if (i - startingIndex > 1) {
if (hasBothKeyValuePair || i - startingIndex > 1) {
// Optimization: Replace '+' with space
if (keyHasPlus) {
key = key.replaceAll("+", " ");
}

if (valueHasPlus) {
value = value.replaceAll("+", " ");
}

// Optimization: Do not decode if it's not necessary.
if (shouldDecodeKey) {
key = fastDecode(key) || key;
}

if (shouldDecodeValue) {
value = fastDecode(value) || value;
if (hasBothKeyValuePair) {
if (valueHasPlus) {
value = value.replaceAll("+", " ");
}

if (shouldDecodeValue) {
value = fastDecode(value) || value;
}
}

if (result[key] === undefined) {
Expand All @@ -82,6 +85,7 @@ function parse(input) {
shouldDecodeValue = false;
keyHasPlus = false;
valueHasPlus = false;
hasBothKeyValuePair = false;
}
// Check '='
else if (c === 61) {
Expand Down

0 comments on commit 0f4707d

Please sign in to comment.