源代码: lib/util.js
util 模块支持 Node.js 内部 API 的需求。
许多实用工具对应用程序和模块开发者也很有用。
要访问它:
const util = require('util');
util.callbackify(original)#original <Function> async 函数采用 async 函数(或返回 Promise 的函数)并返回遵循错误优先回调风格的函数,即将 (err, value) => ... 回调作为最后一个参数。
在回调中,第一个参数将是拒绝原因(如果 Promise 已解决,则为 null),第二个参数将是已解决的值。
const util = require('util');
async function fn() {
return 'hello world';
}
const callbackFunction = util.callbackify(fn);
callbackFunction((err, ret) => {
if (err) throw err;
console.log(ret);
});
将打印:
hello world
回调是异步执行的,并且将具有有限的堆栈跟踪。
如果回调抛出,进程将触发 'uncaughtException' 事件,如果不处理将退出。
由于 null 作为回调的第一个参数有特殊含义,如果封装的函数使用假值为理由来拒绝 Promise,则该值被封装在 Error 中,原始值存储在名为 reason 的字段中。
function fn() {
return Promise.reject(null);
}
const callbackFunction = util.callbackify(fn);
callbackFunction((err, ret) => {
// 当 Promise 使用 `null` 拒绝时,它会使用 Error 封装,
// 原始值存储在 `reason` 中。
err && Object.hasOwn(err, 'reason') && err.reason === null; // true
});
util.debuglog(section[, callback])#section <string> 标识正在为其创建 debuglog 函数的应用程序部分的字符串。callback <Function> 第一次调用日志函数时调用的回调函数参数是更优化的日志函数。util.debuglog() 方法用于创建函数,该函数根据 NODE_DEBUG 环境变量的存在有条件地将调试消息写入 stderr。
如果 section 名称出现在该环境变量的值中,则返回的函数的操作类似于 console.error()。
如果不是,则返回的函数是空操作。
const util = require('util');
const debuglog = util.debuglog('foo');
debuglog('hello from foo [%d]', 123);
如果这个程序在环境中与 NODE_DEBUG=foo 一起运行,则它会输出如下内容:
FOO 3245: hello from foo [123]
其中 3245 是进程 ID。
如果它没有使用该环境变量集运行,则它不会打印任何内容。
section 还支持通配符:
const util = require('util');
const debuglog = util.debuglog('foo-bar');
debuglog('hi there, it\'s foo-bar [%d]', 2333);
如果它在环境中与 NODE_DEBUG=foo* 一起运行,则它将输出如下内容:
FOO-BAR 3257: hi there, it's foo-bar [2333]
可以在 NODE_DEBUG 环境变量中指定多个逗号分隔的 section 名称:NODE_DEBUG=fs,net,tls。
可选的 callback 参数可用于用一个不同的函数替换日志函数,该函数没有任何初始化或不必要的封装。
const util = require('util');
let debuglog = util.debuglog('internals', (debug) => {
// 如果启用该部分,
// 则替换为优化测试的日志记录函数
debuglog = debug;
});
debuglog().enabled#util.debuglog().enabled 获取器用于基于 NODE_DEBUG 环境变量的存在创建可用于条件的测试。
如果 section 名称出现在该环境变量的值中,则返回值将为 true。
如果不是,则返回值将是 false。
const util = require('util');
const enabled = util.debuglog('foo').enabled;
if (enabled) {
console.log('hello from foo [%d]', 123);
}
如果这个程序在环境中与 NODE_DEBUG=foo 一起运行,则它会输出如下内容:
hello from foo [123]
util.debug(section)#util.debuglog 的别名。
当仅使用 util.debuglog().enabled 时,使用允许可读性并不意味着日志记录。
util.deprecate(fn, msg[, code])#fn <Function> 被弃用的函数。msg <string> 调用弃用的函数时显示的警告消息。code <string> 弃用代码。
有关代码的列表,请参阅弃用的 API 列表。util.deprecate() 方法以标记为已弃用的方式封装 fn(可能是函数或类)。
const util = require('util');
exports.obsoleteFunction = util.deprecate(() => {
// 在这里做点事情。
}, 'obsoleteFunction() is deprecated. Use newShinyFunction() instead.');
当调用时,util.deprecate() 将返回将使用 'warning' 事件触发 DeprecationWarning 的函数。
第一次调用返回的函数时,警告将触发并打印到 stderr。
触发警告后,将调用封装的函数而不触发警告。
如果在多次调用 util.deprecate() 时提供了相同的可选 code,则该 code 只会触发一次警告。
const util = require('util');
const fn1 = util.deprecate(someFunction, someMessage, 'DEP0001');
const fn2 = util.deprecate(someOtherFunction, someOtherMessage, 'DEP0001');
fn1(); // 使用代码 DEP0001 触发弃用警告
fn2(); // 不触发弃用警告,因为它具有相同的代码
如果使用 --no-deprecation 或 --no-warnings 命令行标志、或者如果 process.noDeprecation 属性在第一次弃用警告之前设置为 true,则 util.deprecate() 方法不执行任何操作。
如果设置了 --trace-deprecation 或 --trace-warnings 命令行标志、或者 process.traceDeprecation 属性设置为 true,则在第一次调用已弃用的函数时会向 stderr 打印警告和堆栈跟踪。
如果设置了 --throw-deprecation 命令行标志、或者 process.throwDeprecation 属性设置为 true,则在调用已弃用的函数时将抛出异常。
--throw-deprecation 命令行标志和 process.throwDeprecation 属性优先于 --trace-deprecation 和 process.traceDeprecation。
util.format(format[, ...args])#format <string> 类似 printf 的格式字符串。util.format() 方法使用第一个参数作为类似 printf 的格式字符串(其可以包含零个或多个格式说明符)来返回格式化的字符串。
每个说明符都替换为来自相应参数的转换后的值。
支持的说明符有:
%s: String 将用于转换除 BigInt、Object 和 -0 之外的所有值。
BigInt 值将用 n 表示,没有用户定义的 toString 函数的对象使用具有选项 { depth: 0, colors: false, compact: 3 } 的 util.inspect() 进行检查。%d: Number 将用于转换除 BigInt 和 Symbol 之外的所有值。%i: parseInt(value, 10) 用于除 BigInt 和 Symbol 之外的所有值。%f: parseFloat(value) 用于除 Symbol 之外的所有值。%j: JSON。
如果参数包含循环引用,则替换为字符串 '[Circular]'。%o: Object.
具有通用 JavaScript 对象格式的对象的字符串表示形式。
类似于具有选项 { showHidden: true, showProxy: true } 的 util.inspect()。
这将显示完整的对象,包括不可枚举的属性和代理。%O: Object.
具有通用 JavaScript 对象格式的对象的字符串表示形式。
类似于没有选项的 util.inspect()。
这将显示完整的对象,但不包括不可枚举的属性和代理。%c: CSS.
此说明符被忽略,将跳过任何传入的 CSS。%%: 单个百分号 ('%')。
这不消费参数。如果说明符没有相应的参数,则不会替换它:
util.format('%s:%s', 'foo');
// 返回: 'foo:%s'
如果其类型不是 string,则不属于格式字符串的值将使用 util.inspect() 进行格式化。
如果传给 util.format() 方法的参数多于说明符的数量,则额外的参数将以空格分隔串联到返回的字符串:
util.format('%s:%s', 'foo', 'bar', 'baz');
// 返回: 'foo:bar baz'
如果第一个参数不包含有效的格式说明符,则 util.format() 返回以空格分隔的所有参数的串联的字符串:
util.format(1, 2, 3);
// 返回: '1 2 3'
如果只有一个参数传给 util.format(),则它会按原样返回,不进行任何格式化:
util.format('%% %s');
// 返回: '%% %s'
util.format() 是同步的方法,旨在用作调试工具。
某些输入值可能会产生显着的性能开销,从而阻塞事件循环。
小心使用此函数,切勿在热代码路径中使用。
util.formatWithOptions(inspectOptions, format[, ...args])#此函数与 util.format() 相同,不同之处在于它接受 inspectOptions 参数,该参数指定传给 util.inspect() 的选项。
util.formatWithOptions({ colors: true }, 'See object %O', { foo: 42 });
// 返回 'See object { foo: 42 }',
// 其中 `42` 在打印到终端时被着色为数字。
util.getSystemErrorName(err)#返回来自 Node.js API 的数字错误码的字符串名称。 错误码和错误名称之间的映射是平台相关的。 有关常见错误的名称,请参阅常见的系统错误。
fs.access('file/that/does/not/exist', (err) => {
const name = util.getSystemErrorName(err.errno);
console.error(name); // ENOENT
});
util.getSystemErrorMap()#返回来自 Node.js API 的可用的所有系统错误码的映射。 错误码和错误名称之间的映射是平台相关的。 有关常见错误的名称,请参阅常见的系统错误。
fs.access('file/that/does/not/exist', (err) => {
const errorMap = util.getSystemErrorMap();
const name = errorMap.get(err.errno);
console.error(name); // ENOENT
});
util.inherits(constructor, superConstructor)#extends 关键字。constructor <Function>superConstructor <Function>不鼓励使用 util.inherits()。
请使用 ES6 class 和 extends 关键字来获得语言级别的继承支持。
另请注意,这两种风格在语义上不兼容。
将原型方法从一个构造函数继承到另一个构造函数。
constructor 的原型将被设置为从 superConstructor 创建的新对象。
这主要是在 Object.setPrototypeOf(constructor.prototype, superConstructor.prototype) 之上添加了一些输入验证。
作为额外的便利,superConstructor 将可通过 constructor.super_ 属性访问。
const util = require('util');
const EventEmitter = require('events');
function MyStream() {
EventEmitter.call(this);
}
util.inherits(MyStream, EventEmitter);
MyStream.prototype.write = function(data) {
this.emit('data', data);
};
const stream = new MyStream();
console.log(stream instanceof EventEmitter); // true
console.log(MyStream.super_ === EventEmitter); // true
stream.on('data', (data) => {
console.log(`Received data: "${data}"`);
});
stream.write('It works!'); // 接收到的数据:"It works!"
使用 class 和 extends 的 ES6 示例:
const EventEmitter = require('events');
class MyStream extends EventEmitter {
write(data) {
this.emit('data', data);
}
}
const stream = new MyStream();
stream.on('data', (data) => {
console.log(`Received data: "${data}"`);
});
stream.write('With ES6');
util.inspect(object[, options])#util.inspect(object[, showHidden[, depth[, colors]]])object <any> 任何 JavaScript 原始类型或 Object。options <Object>
showHidden <boolean> 如果为 true,则 object 的不可枚举符号和属性包含在格式化的结果中。
WeakMap 和 WeakSet 条目以及用户定义的原型属性(不包括方法属性)也包括在内。 默认值: false。depth <number> 指定格式化 object 时递归的次数。
这对于检查大型对象很有用。
要递归到最大调用堆栈大小,则传入 Infinity 或 null。
默认值: 2。colors <boolean> 如果为 true,则输出的样式为 ANSI 颜色代码。
颜色是可自定义的。
参阅自定义 util.inspect 颜色。
默认值: false。customInspect <boolean> 如果为 false,则 [util.inspect.custom](depth, opts, inspect) 函数不被调用。
默认值: true。showProxy <boolean> 如果为 true,则 Proxy 检查包括 target 和 handler 对象。 默认值: false。maxArrayLength <integer> 指定格式化时要包含的 Array、TypedArray、WeakMap 和 WeakSet 元素的最大数量。
设置为 null 或 Infinity 则显示所有元素。
设置为 0 或负数则不显示任何元素。 默认值: 100。maxStringLength <integer> 指定格式化时要包含的最大字符数。
设置为 null 或 Infinity 则显示所有元素。
设置为 0 或负数则不显示字符。 默认值: 10000。breakLength <integer> 输入值在多行中拆分的长度。
设置为 Infinity 则将输入格式化为单行(与设置为 true 或任何数字 >= 1 的 compact 组合)。
默认值: 80。compact <boolean> | <integer> 将此设置为 false 会导致每个对象的键显示在新行上。
它将在比 breakLength 长的文本中换行。
如果设置为数字,则只要所有属性都适合 breakLength,则最多 n 个内部元素将合并在一行中。
短数组元素也组合在一起。
有关更多信息,请参阅下面的示例。 默认值: 3。sorted <boolean> | <Function> 如果设置为 true 或函数,则对象的所有属性以及 Set 和 Map 条目都将在结果字符串中排序。
如果设置为 true,则使用默认的排序。
如果设置为函数,则用作比较函数。getters <boolean> | <string> 如果设置为 true,则检查获取器。
如果设置为 'get',则只检查没有相应设置器的获取器。
如果设置为 'set',则只检查具有相应设置器的获取器。
这可能会导致副作用,具体取决于获取器函数。
默认值: false。numericSeparator <boolean> 如果设置为 true,则使用下划线分隔所有 bigint 和数字中的每三个数字。
默认值: false。object 的表示。util.inspect() 方法返回用于调试的 object 的字符串表示。
util.inspect 的输出可能随时更改,不应以编程方式依赖。
可以传入额外的 options 来改变结果。
util.inspect() 将使用构造函数的名称和/或 @@toStringTag 为检查的值制作可识别的标签。
class Foo {
get [Symbol.toStringTag]() {
return 'bar';
}
}
class Bar {}
const baz = Object.create(null, { [Symbol.toStringTag]: { value: 'foo' } });
util.inspect(new Foo()); // 'Foo [bar] {}'
util.inspect(new Bar()); // 'Bar {}'
util.inspect(baz); // '[foo] {}'
循环引用通过使用引用索引指向其锚点:
const { inspect } = require('util');
const obj = {};
obj.a = [obj];
obj.b = {};
obj.b.inner = obj.b;
obj.b.obj = obj;
console.log(inspect(obj));
// <ref *1> {
// a: [ [Circular *1] ],
// b: <ref *2> { inner: [Circular *2], obj: [Circular *1] }
// }
以下示例检查 util 对象的所有属性:
const util = require('util');
console.log(util.inspect(util, { showHidden: true, depth: null }));
以下示例高亮了 compact 选项的效果:
const util = require('util');
const o = {
a: [1, 2, [[
'Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit, sed do ' +
'eiusmod \ntempor incididunt ut labore et dolore magna aliqua.',
'test',
'foo']], 4],
b: new Map([['za', 1], ['zb', 'test']])
};
console.log(util.inspect(o, { compact: true, depth: 5, breakLength: 80 }));
// { a:
// [ 1,
// 2,
// [ [ 'Lorem ipsum dolor sit amet,\nconsectetur [...]', // A long line
// 'test',
// 'foo' ] ],
// 4 ],
// b: Map(2) { 'za' => 1, 'zb' => 'test' } }
// 将 `compact` 设置为 false 或整数会创建更友好的输出。
console.log(util.inspect(o, { compact: false, depth: 5, breakLength: 80 }));
// {
// a: [
// 1,
// 2,
// [
// [
// 'Lorem ipsum dolor sit amet,\n' +
// 'consectetur adipiscing elit, sed do eiusmod \n' +
// 'tempor incididunt ut labore et dolore magna aliqua.',
// 'test',
// 'foo'
// ]
// ],
// 4
// ],
// b: Map(2) {
// 'za' => 1,
// 'zb' => 'test'
// }
// }
// 将 `breakLength` 设置为例如 150,
// 则将在一行中打印 "Lorem ipsum" 文本。
showHidden 选项允许检查 WeakMap 和 WeakSet 条目。
如果条目多于 maxArrayLength,则无法保证显示哪些条目。
这意味着两次检索相同的 WeakSet 条目可能会导致不同的输出。
此外,没有剩余强引用的条目可能随时被垃圾回收。
const { inspect } = require('util');
const obj = { a: 1 };
const obj2 = { b: 2 };
const weakSet = new WeakSet([obj, obj2]);
console.log(inspect(weakSet, { showHidden: true }));
// WeakSet { { a: 1 }, { b: 2 } }
sorted 选项确保对象的属性插入顺序不会影响 util.inspect() 的结果。
const { inspect } = require('util');
const assert = require('assert');
const o1 = {
b: [2, 3, 1],
a: '`a` comes before `b`',
c: new Set([2, 3, 1])
};
console.log(inspect(o1, { sorted: true }));
// { a: '`a` comes before `b`', b: [ 2, 3, 1 ], c: Set(3) { 1, 2, 3 } }
console.log(inspect(o1, { sorted: (a, b) => b.localeCompare(a) }));
// { c: Set(3) { 3, 2, 1 }, b: [ 2, 3, 1 ], a: '`a` comes before `b`' }
const o2 = {
c: new Set([2, 1, 3]),
a: '`a` comes before `b`',
b: [2, 3, 1]
};
assert.strict.equal(
inspect(o1, { sorted: true }),
inspect(o2, { sorted: true })
);
numericSeparator 选项为所有数字每三位添加一个下划线。
const { inspect } = require('util');
const thousand = 1_000;
const million = 1_000_000;
const bigNumber = 123_456_789n;
const bigDecimal = 1_234.123_45;
console.log(thousand, million, bigNumber, bigDecimal);
// 1_000 1_000_000 123_456_789n 1_234.123_45
util.inspect() 是用于调试的同步方法。
其最大输出长度约为 128 MB。
造成更长输出的输入将被截断。
util.inspect 的颜色输出(如果启用)可通过 util.inspect.styles 和 util.inspect.colors 属性全局地自定义。
util.inspect.styles 是将样式名称与来自 util.inspect.colors 的颜色相关联的映射。
默认的样式和相关的颜色为:
bigint: yellowboolean: yellowdate: magentamodule: underlinename: (没有样式)null: boldnumber: yellowregexp: redspecial: cyan(例如,Proxies)string: greensymbol: greenundefined: grey颜色样式使用 ANSI 控制代码,可能并非所有终端都支持。
要验证颜色支持,则使用 tty.hasColors()。
下面列出了预定义的控制代码(分组为“修饰符”、“前景色”和“背景色”)。
修饰符的支持因不同的终端而异。 如果不支持,则它们通常会被忽略。
reset - 将所有(颜色)修饰符重置为其默认值strikeThrough, crossedout, crossedOut)hidden - 打印文本,但使其不可见(别名:conceal)faint)swapcolors、swapColors)doubleUnderline)blackredgreenyellowbluemagentacyanwhitegray(别名:grey、blackBright)redBrightgreenBrightyellowBrightblueBrightmagentaBrightcyanBrightwhiteBrightbgBlackbgRedbgGreenbgYellowbgBluebgMagentabgCyanbgWhitebgGray(别名:bgGrey、bgBlackBright)bgRedBrightbgGreenBrightbgYellowBrightbgBlueBrightbgMagentaBrightbgCyanBrightbgWhiteBright对象也可以定义自己的 [util.inspect.custom](depth, opts, inspect) 函数,util.inspect() 将在检查对象时调用并使用其结果。
const util = require('util');
class Box {
constructor(value) {
this.value = value;
}
[util.inspect.custom](depth, options, inspect) {
if (depth < 0) {
return options.stylize('[Box]', 'special');
}
const newOptions = Object.assign({}, options, {
depth: options.depth === null ? null : options.depth - 1
});
// 五个空格填充,因为这是“Box<”的大小。
const padding = ' '.repeat(5);
const inner = inspect(this.value, newOptions)
.replace(/\n/g, `\n${padding}`);
return `${options.stylize('Box', 'special')}< ${inner} >`;
}
}
const box = new Box(true);
util.inspect(box);
// 返回: "Box< true >"
自定义的 [util.inspect.custom](depth, opts, inspect) 函数通常返回一个字符串,但也可能返回一个由 util.inspect() 相应格式化的任何类型的值。
const util = require('util');
const obj = { foo: 'this will not show up in the inspect() output' };
obj[util.inspect.custom] = (depth) => {
return { bar: 'baz' };
};
util.inspect(obj);
// 返回: "{ bar: 'baz' }"
util.inspect.custom#除了可以通过 util.inspect.custom 访问之外,此符号是全局地注册,可以在任何环境中作为 Symbol.for('nodejs.util.inspect.custom') 访问。
使用此允许以可移植方式编写代码,以便在 Node.js 环境中使用自定义检查功能并在浏览器中忽略。
util.inspect() 函数本身作为第三个参数传给自定义检查函数以允许进一步的可移植性。
const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom');
class Password {
constructor(value) {