util: improve format performance

PR-URL: https://github.com/nodejs/node/pull/15422
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
This commit is contained in:
Ruben Bridgewater 2017-09-15 15:56:53 -03:00
parent 6f340762d8
commit faaefa8082
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
2 changed files with 64 additions and 65 deletions

View File

@ -2,35 +2,30 @@
const util = require('util'); const util = require('util');
const common = require('../common'); const common = require('../common');
const types = [
'string',
'number',
'object',
'unknown',
'no-replace'
];
const bench = common.createBenchmark(main, {
n: [2e6],
type: types
});
const inputs = { const inputs = {
'string': ['Hello, my name is %s', 'fred'], 'string': ['Hello, my name is %s', 'Fred'],
'number': ['Hi, I was born in %d', 1942], 'string-2': ['Hello, %s is my name', 'Fred'],
'object': ['An error occurred %j', { msg: 'This is an error', code: 'ERR' }], 'number': ['Hi, I was born in %d', 1989],
'replace-object': ['An error occurred %j', { msg: 'This is an error' }],
'unknown': ['hello %a', 'test'], 'unknown': ['hello %a', 'test'],
'no-replace': [1, 2] 'no-replace': [1, 2],
'no-replace-2': ['foobar', 'yeah', 'mensch', 5],
'only-objects': [{ msg: 'This is an error' }, { msg: 'This is an error' }],
'many-%': ['replace%%%%s%%%%many%s%s%s', 'percent'],
}; };
function main(conf) { const bench = common.createBenchmark(main, {
const n = conf.n | 0; n: [4e6],
const type = conf.type; type: Object.keys(inputs)
});
const input = inputs[type]; function main({ n, type }) {
const [first, second] = inputs[type];
bench.start(); bench.start();
for (var i = 0; i < n; i++) { for (var i = 0; i < n; i++) {
util.format(input[0], input[1]); util.format(first, second);
} }
bench.end(n); bench.end(n);
} }

View File

@ -177,12 +177,16 @@ function tryStringify(arg) {
} }
function format(f) { function format(f) {
var i, tempStr;
if (typeof f !== 'string') { if (typeof f !== 'string') {
const objects = new Array(arguments.length); if (arguments.length === 0) return '';
for (var index = 0; index < arguments.length; index++) { var res = '';
objects[index] = inspect(arguments[index]); for (i = 0; i < arguments.length - 1; i++) {
res += inspect(arguments[i]);
res += ' ';
} }
return objects.join(' '); res += inspect(arguments[i]);
return res;
} }
if (arguments.length === 1) return f; if (arguments.length === 1) return f;
@ -190,49 +194,49 @@ function format(f) {
var str = ''; var str = '';
var a = 1; var a = 1;
var lastPos = 0; var lastPos = 0;
for (var i = 0; i < f.length;) { for (i = 0; i < f.length - 1; i++) {
if (f.charCodeAt(i) === 37/*'%'*/ && i + 1 < f.length) { if (f.charCodeAt(i) === 37) { // '%'
if (f.charCodeAt(i + 1) !== 37/*'%'*/ && a >= arguments.length) { const nextChar = f.charCodeAt(++i);
++i; if (a !== arguments.length) {
continue; switch (nextChar) {
} case 115: // 's'
if (lastPos < i) tempStr = String(arguments[a++]);
str += f.slice(lastPos, i);
switch (f.charCodeAt(i + 1)) {
case 100: // 'd'
str += Number(arguments[a++]);
break;
case 105: // 'i'
str += parseInt(arguments[a++]);
break;
case 102: // 'f'
str += parseFloat(arguments[a++]);
break; break;
case 106: // 'j' case 106: // 'j'
str += tryStringify(arguments[a++]); tempStr = tryStringify(arguments[a++]);
break; break;
case 115: // 's' case 100: // 'd'
str += String(arguments[a++]); tempStr = `${Number(arguments[a++])}`;
break; break;
case 79: // 'O' case 79: // 'O'
str += inspect(arguments[a++]); tempStr = inspect(arguments[a++]);
break; break;
case 111: // 'o' case 111: // 'o'
str += inspect(arguments[a++], tempStr = inspect(arguments[a++],
{ showHidden: true, depth: 4, showProxy: true }); { showHidden: true, depth: 4, showProxy: true });
break; break;
case 37: // '%' case 105: // 'i'
str += '%'; tempStr = `${parseInt(arguments[a++])}`;
break; break;
case 102: // 'f'
tempStr = `${parseFloat(arguments[a++])}`;
break;
case 37: // '%'
str += f.slice(lastPos, i);
lastPos = i + 1;
continue;
default: // any other character is not a correct placeholder default: // any other character is not a correct placeholder
str += '%';
lastPos = i = i + 1;
continue; continue;
} }
lastPos = i = i + 2; if (lastPos !== i - 1)
continue; str += f.slice(lastPos, i - 1);
str += tempStr;
lastPos = i + 1;
} else if (nextChar === 37) {
str += f.slice(lastPos, i);
lastPos = i + 1;
}
} }
++i;
} }
if (lastPos === 0) if (lastPos === 0)
str = f; str = f;
@ -240,7 +244,7 @@ function format(f) {
str += f.slice(lastPos); str += f.slice(lastPos);
while (a < arguments.length) { while (a < arguments.length) {
const x = arguments[a++]; const x = arguments[a++];
if (x === null || (typeof x !== 'object' && typeof x !== 'symbol')) { if ((typeof x !== 'object' && typeof x !== 'symbol') || x === null) {
str += ` ${x}`; str += ` ${x}`;
} else { } else {
str += ` ${inspect(x)}`; str += ` ${inspect(x)}`;