Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d2125d5

Browse files
committedSep 15, 2017
util: improve format performance
1 parent a591610 commit d2125d5

File tree

2 files changed

+70
-66
lines changed

2 files changed

+70
-66
lines changed
 

‎benchmark/util/format.js

+15-20
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,30 @@
22

33
const util = require('util');
44
const common = require('../common');
5-
const types = [
6-
'string',
7-
'number',
8-
'object',
9-
'unknown',
10-
'no-replace'
11-
];
12-
const bench = common.createBenchmark(main, {
13-
n: [2e6],
14-
type: types
15-
});
165

176
const inputs = {
18-
'string': ['Hello, my name is %s', 'fred'],
19-
'number': ['Hi, I was born in %d', 1942],
20-
'object': ['An error occurred %j', { msg: 'This is an error', code: 'ERR' }],
7+
'string': ['Hello, my name is %s', 'Fred'],
8+
'string-2': ['Hello, %s is my name', 'Fred'],
9+
'number': ['Hi, I was born in %d', 1989],
10+
'replace-object': ['An error occurred %j', { msg: 'This is an error' }],
2111
'unknown': ['hello %a', 'test'],
22-
'no-replace': [1, 2]
12+
'no-replace': [1, 2],
13+
'no-replace-2': ['foobar', 'yeah', 'mensch', 5],
14+
'only-objects': [{ msg: 'This is an error' }, { msg: 'This is an error' }],
15+
'many-%': ['replace%%%%s%%%%many%s%s%s', 'percent'],
2316
};
2417

25-
function main(conf) {
26-
const n = conf.n | 0;
27-
const type = conf.type;
18+
const bench = common.createBenchmark(main, {
19+
n: [4e6],
20+
type: Object.keys(inputs)
21+
});
2822

29-
const input = inputs[type];
23+
function main({ n, type }) {
24+
const [first, second] = inputs[type];
3025

3126
bench.start();
3227
for (var i = 0; i < n; i++) {
33-
util.format(input[0], input[1]);
28+
util.format(first, second);
3429
}
3530
bench.end(n);
3631
}

‎lib/util.js

+55-46
Original file line numberDiff line numberDiff line change
@@ -177,70 +177,79 @@ function tryStringify(arg) {
177177
}
178178

179179
function format(f) {
180+
var i, tempStr;
180181
if (typeof f !== 'string') {
181-
const objects = new Array(arguments.length);
182-
for (var index = 0; index < arguments.length; index++) {
183-
objects[index] = inspect(arguments[index]);
182+
if (arguments.length === 0) return '';
183+
var res = '';
184+
for (i = 0; i < arguments.length - 1; i++) {
185+
res += inspect(arguments[i]);
186+
res += ' ';
184187
}
185-
return objects.join(' ');
188+
res += inspect(arguments[i]);
189+
return res;
186190
}
187191

188192
if (arguments.length === 1) return f;
189193

190194
var str = '';
191195
var a = 1;
192196
var lastPos = 0;
193-
for (var i = 0; i < f.length;) {
194-
if (f.charCodeAt(i) === 37/*'%'*/ && i + 1 < f.length) {
195-
if (f.charCodeAt(i + 1) !== 37/*'%'*/ && a >= arguments.length) {
196-
++i;
197-
continue;
198-
}
199-
if (lastPos < i)
200-
str += f.slice(lastPos, i);
201-
switch (f.charCodeAt(i + 1)) {
202-
case 100: // 'd'
203-
str += Number(arguments[a++]);
204-
break;
205-
case 105: // 'i'
206-
str += parseInt(arguments[a++]);
207-
break;
208-
case 102: // 'f'
209-
str += parseFloat(arguments[a++]);
210-
break;
211-
case 106: // 'j'
212-
str += tryStringify(arguments[a++]);
213-
break;
214-
case 115: // 's'
215-
str += String(arguments[a++]);
216-
break;
217-
case 79: // 'O'
218-
str += inspect(arguments[a++]);
219-
break;
220-
case 111: // 'o'
221-
str += inspect(arguments[a++],
222-
{ showHidden: true, depth: 4, showProxy: true });
223-
break;
224-
case 37: // '%'
225-
str += '%';
226-
break;
227-
default: // any other character is not a correct placeholder
228-
str += '%';
229-
lastPos = i = i + 1;
230-
continue;
197+
for (i = 0; i < f.length - 1; i++) {
198+
if (f.charCodeAt(i) === 37) { // '%'
199+
if (a !== arguments.length) {
200+
switch (f.charCodeAt(i + 1)) {
201+
case 115: // 's'
202+
tempStr = String(arguments[a++]);
203+
break;
204+
case 106: // 'j'
205+
tempStr = tryStringify(arguments[a++]);
206+
break;
207+
case 100: // 'd'
208+
tempStr = `${Number(arguments[a++])}`;
209+
break;
210+
case 79: // 'O'
211+
tempStr = inspect(arguments[a++]);
212+
break;
213+
case 111: // 'o'
214+
tempStr = inspect(arguments[a++],
215+
{ showHidden: true, depth: 4, showProxy: true });
216+
break;
217+
case 105: // 'i'
218+
tempStr = `${parseInt(arguments[a++])}`;
219+
break;
220+
case 102: // 'f'
221+
tempStr = `${parseFloat(arguments[a++])}`;
222+
break;
223+
case 37: // '%'
224+
i++;
225+
str += f.slice(lastPos, i);
226+
lastPos = i + 1;
227+
continue;
228+
default: // any other character is not a correct placeholder
229+
i++;
230+
continue;
231+
}
232+
if (lastPos !== i)
233+
str += f.slice(lastPos, i);
234+
str += tempStr;
235+
i++;
236+
lastPos = i + 1;
237+
} else {
238+
i++;
239+
if (f.charCodeAt(i) === 37) {
240+
str += f.slice(lastPos, i);
241+
lastPos = i + 1;
242+
}
231243
}
232-
lastPos = i = i + 2;
233-
continue;
234244
}
235-
++i;
236245
}
237246
if (lastPos === 0)
238247
str = f;
239248
else if (lastPos < f.length)
240249
str += f.slice(lastPos);
241250
while (a < arguments.length) {
242251
const x = arguments[a++];
243-
if (x === null || (typeof x !== 'object' && typeof x !== 'symbol')) {
252+
if ((typeof x !== 'object' && typeof x !== 'symbol') || x === null) {
244253
str += ` ${x}`;
245254
} else {
246255
str += ` ${inspect(x)}`;

0 commit comments

Comments
 (0)
Please sign in to comment.