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:
parent
6f340762d8
commit
faaefa8082
@ -2,35 +2,30 @@
|
||||
|
||||
const util = require('util');
|
||||
const common = require('../common');
|
||||
const types = [
|
||||
'string',
|
||||
'number',
|
||||
'object',
|
||||
'unknown',
|
||||
'no-replace'
|
||||
];
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [2e6],
|
||||
type: types
|
||||
});
|
||||
|
||||
const inputs = {
|
||||
'string': ['Hello, my name is %s', 'fred'],
|
||||
'number': ['Hi, I was born in %d', 1942],
|
||||
'object': ['An error occurred %j', { msg: 'This is an error', code: 'ERR' }],
|
||||
'string': ['Hello, my name is %s', 'Fred'],
|
||||
'string-2': ['Hello, %s is my name', 'Fred'],
|
||||
'number': ['Hi, I was born in %d', 1989],
|
||||
'replace-object': ['An error occurred %j', { msg: 'This is an error' }],
|
||||
'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 n = conf.n | 0;
|
||||
const type = conf.type;
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [4e6],
|
||||
type: Object.keys(inputs)
|
||||
});
|
||||
|
||||
const input = inputs[type];
|
||||
function main({ n, type }) {
|
||||
const [first, second] = inputs[type];
|
||||
|
||||
bench.start();
|
||||
for (var i = 0; i < n; i++) {
|
||||
util.format(input[0], input[1]);
|
||||
util.format(first, second);
|
||||
}
|
||||
bench.end(n);
|
||||
}
|
||||
|
94
lib/util.js
94
lib/util.js
@ -177,12 +177,16 @@ function tryStringify(arg) {
|
||||
}
|
||||
|
||||
function format(f) {
|
||||
var i, tempStr;
|
||||
if (typeof f !== 'string') {
|
||||
const objects = new Array(arguments.length);
|
||||
for (var index = 0; index < arguments.length; index++) {
|
||||
objects[index] = inspect(arguments[index]);
|
||||
if (arguments.length === 0) return '';
|
||||
var res = '';
|
||||
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;
|
||||
@ -190,49 +194,49 @@ function format(f) {
|
||||
var str = '';
|
||||
var a = 1;
|
||||
var lastPos = 0;
|
||||
for (var i = 0; i < f.length;) {
|
||||
if (f.charCodeAt(i) === 37/*'%'*/ && i + 1 < f.length) {
|
||||
if (f.charCodeAt(i + 1) !== 37/*'%'*/ && a >= arguments.length) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (lastPos < i)
|
||||
for (i = 0; i < f.length - 1; i++) {
|
||||
if (f.charCodeAt(i) === 37) { // '%'
|
||||
const nextChar = f.charCodeAt(++i);
|
||||
if (a !== arguments.length) {
|
||||
switch (nextChar) {
|
||||
case 115: // 's'
|
||||
tempStr = String(arguments[a++]);
|
||||
break;
|
||||
case 106: // 'j'
|
||||
tempStr = tryStringify(arguments[a++]);
|
||||
break;
|
||||
case 100: // 'd'
|
||||
tempStr = `${Number(arguments[a++])}`;
|
||||
break;
|
||||
case 79: // 'O'
|
||||
tempStr = inspect(arguments[a++]);
|
||||
break;
|
||||
case 111: // 'o'
|
||||
tempStr = inspect(arguments[a++],
|
||||
{ showHidden: true, depth: 4, showProxy: true });
|
||||
break;
|
||||
case 105: // 'i'
|
||||
tempStr = `${parseInt(arguments[a++])}`;
|
||||
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
|
||||
continue;
|
||||
}
|
||||
if (lastPos !== i - 1)
|
||||
str += f.slice(lastPos, i - 1);
|
||||
str += tempStr;
|
||||
lastPos = i + 1;
|
||||
} else if (nextChar === 37) {
|
||||
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;
|
||||
case 106: // 'j'
|
||||
str += tryStringify(arguments[a++]);
|
||||
break;
|
||||
case 115: // 's'
|
||||
str += String(arguments[a++]);
|
||||
break;
|
||||
case 79: // 'O'
|
||||
str += inspect(arguments[a++]);
|
||||
break;
|
||||
case 111: // 'o'
|
||||
str += inspect(arguments[a++],
|
||||
{ showHidden: true, depth: 4, showProxy: true });
|
||||
break;
|
||||
case 37: // '%'
|
||||
str += '%';
|
||||
break;
|
||||
default: // any other character is not a correct placeholder
|
||||
str += '%';
|
||||
lastPos = i = i + 1;
|
||||
continue;
|
||||
lastPos = i + 1;
|
||||
}
|
||||
lastPos = i = i + 2;
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (lastPos === 0)
|
||||
str = f;
|
||||
@ -240,7 +244,7 @@ function format(f) {
|
||||
str += f.slice(lastPos);
|
||||
while (a < arguments.length) {
|
||||
const x = arguments[a++];
|
||||
if (x === null || (typeof x !== 'object' && typeof x !== 'symbol')) {
|
||||
if ((typeof x !== 'object' && typeof x !== 'symbol') || x === null) {
|
||||
str += ` ${x}`;
|
||||
} else {
|
||||
str += ` ${inspect(x)}`;
|
||||
|
Loading…
x
Reference in New Issue
Block a user