Skip to content
0

node:util

node:util 提供了许多工具函数,

TIP

如果你想在浏览器环境也使用 node:util 里面的工具函数,可以使用 browserify/node-util 这个 NPM 包

注意 browserify/node-util 里面导出的函数并不完全和 node:util 一致,使用特定的函数前请检查是否支持

原型继承

inherits 是一个实现对象间原型继承的函数。

function Base() {
    this.name = 'base';
}
Base.prototype.showName = function() {
    console.log(this.name);
};
function Sub() {
    this.name = 'sub';
}

inherits(Sub, Base);

所构建的对象关系如下图所示:

接下来对二者实例化

var objBase = new Base();
objBase.showName(); // 'base'

var objSub = new Sub();
objSub.showName(); // 'sub'

得到关系:

inspect

inspect 用于它可以将一个对象转换为字符串,显示对象的详细信息,函数签名如下,

export function inspect(object: any, showHidden?: boolean, depth?: number | null, color?: boolean): string;
export function inspect(object: any, options?: InspectOptions): string;
InspectOptions 的类型定义
export interface InspectOptions {
    /**
     * If `true`, object's non-enumerable symbols and properties are included in the formatted result.
     * `WeakMap` and `WeakSet` entries are also included as well as user defined prototype properties (excluding method properties).
     * @default false
     */
    showHidden?: boolean | undefined;
    /**
     * Specifies the number of times to recurse while formatting object.
     * This is useful for inspecting large objects.
     * To recurse up to the maximum call stack size pass `Infinity` or `null`.
     * @default 2
     */
    depth?: number | null | undefined;
    /**
     * If `true`, the output is styled with ANSI color codes. Colors are customizable.
     */
    colors?: boolean | undefined;
    /**
     * If `false`, `[util.inspect.custom](depth, opts, inspect)` functions are not invoked.
     * @default true
     */
    customInspect?: boolean | undefined;
    /**
     * If `true`, `Proxy` inspection includes the target and handler objects.
     * @default false
     */
    showProxy?: boolean | undefined;
    /**
     * Specifies the maximum number of `Array`, `TypedArray`, `WeakMap`, and `WeakSet` elements
     * to include when formatting. Set to `null` or `Infinity` to show all elements.
     * Set to `0` or negative to show no elements.
     * @default 100
     */
    maxArrayLength?: number | null | undefined;
    /**
     * Specifies the maximum number of characters to
     * include when formatting. Set to `null` or `Infinity` to show all elements.
     * Set to `0` or negative to show no characters.
     * @default 10000
     */
    maxStringLength?: number | null | undefined;
    /**
     * The length at which input values are split across multiple lines.
     * Set to `Infinity` to format the input as a single line
     * (in combination with `compact` set to `true` or any number >= `1`).
     * @default 80
     */
    breakLength?: number | undefined;
    /**
     * Setting this to `false` causes each object key
     * to be displayed on a new line. It will also add new lines to text that is
     * longer than `breakLength`. If set to a number, the most `n` inner elements
     * are united on a single line as long as all properties fit into
     * `breakLength`. Short array elements are also grouped together. Note that no
     * text will be reduced below 16 characters, no matter the `breakLength` size.
     * For more information, see the example below.
     * @default true
     */
    compact?: boolean | number | undefined;
    /**
     * If set to `true` or a function, all properties of an object, and `Set` and `Map`
     * entries are sorted in the resulting string.
     * If set to `true` the default sort is used.
     * If set to a function, it is used as a compare function.
     */
    sorted?: boolean | ((a: string, b: string) => number) | undefined;
    /**
     * If set to `true`, getters are going to be
     * inspected as well. If set to `'get'` only getters without setter are going
     * to be inspected. If set to `'set'` only getters having a corresponding
     * setter are going to be inspected. This might cause side effects depending on
     * the getter function.
     * @default false
     */
    getters?: 'get' | 'set' | boolean | undefined;
    /**
     * If set to `true`, an underscore is used to separate every three digits in all bigints and numbers.
     * @default false
     */
    numericSeparator?: boolean | undefined;
}

举个例子:

const obj = {};
Object.defineProperty(obj, 'hidden', {
  enumerable: false,
  value: 'foo'
});

obj.hidden // 'foo' 

util.inspect(obj); // {}
util.inspect(obj, { showHidden: true }); // { hidden: 'foo' }

对于日常使用来说,一个头疼的问题是 NodeJS 在控制台的输出会被折叠,可以通过 inspect 设置第三个参数,控制打印的深度。类型为 number | null

const deepObject = {
    a: {
        b: {
            c: {
                d: 1
            }
        }
    }
}
console.log(deepObject) // depth 默认为 2
/*
{ a: { b: { c: [Object] } } }
*/
console.log(util.inspect(deepObject, false, null)) //=> depth 设置为 null 代表不对深度限制,打印全部
/*
{ a: { b: { c: { d: 1 } } } }
*/

promisify & callbackify

promisify 将一个接受回调的函数转换为返回 Promise 的函数,callbackify 则相反

需要满足的条件

  • promisify 的函数的回调函数需要在函数参数的最后一个位置
  • 回调函数的第一个参数为错误对象 err,第二个参数为成功结果 data
import util from "node:util";
import fs from 'fs'

const readFile = util.promisify(fs.readFile);

readFile('./child.js', 'utf-8').then(data => {
  console.log({ data }) //=> content
}, err => {});

const callbackFunction = util.callbackify(readFile)

callbackFunction('./child.js', 'utf-8', (err, data) => {
    console.log({ data }) //=> content
})

debuglog & debug

用于输出调试信息 ,且 util.debuglog === util.debugtrue,二者是等价的

// index.js
import util from "node:util";
const debug = util.debuglog('foo');

debug('Hello-from-foo');
console.log('end')

默认情况下, debuglog() 创建的函数不会打印任何信息。要启用打印,需要设置NODE_DEBUG 环境变量,所以这在我们调试某些模块的时候特别有用

$ node index.js
end
$ NODE_DEBUG=foo node index.js
Hello-from-foo
end

我们经常使用第三方包 - debug-js/debug 作为原生的替代品,其优势在于:

  • debug 支持更灵活的命名空间方式,用:隔开,例如 debug('app:db')
  • debug 支持颜色、格式化等更丰富的输出选项
  • 支持浏览器

deprecate

deprecate() 用来在函数被调用时显示方法废弃警告信息。例如:

// index.js
import { deprecate } from 'node:util'
const oldFunc = deprecate(() => {
  console.log('hello')
}, 'oldFunc() is deprecated, use newFunc() instead');

oldFunc(); // 输出警告信息

执行结果:

$ node index.js
hello
(node:16920) DeprecationWarning: oldFunc() is deprecated, use newFunc() instead
(Use `node --trace-deprecation ...` to show where the warning was created)

TIP

除此之外,在标记函数过时的信息方面,通常我们会选择 TS 注释的形式,例如

/**
 * @deprecated oldFunc() is deprecated, use newFunc() instead
 */
function oldFunc() {
    //...
}

这能够给用户更完善的 IDEA 提示

format

format 可以用来格式化字符串,它用法类似于C语言中的 printf()

const name = 'John';
const age = 20;

console.log(
    util.format('Hello %s, you are %d', name, age) //=> Hello John, you are 20
)

更多请查看官方文档

isDeepStrictEqual

isDeepStrictEqual 一个深度递归的严格比较两个值是否相等的方法

import { isDeepStrictEqual } from 'node:util'
let obj1 = {
    a: 1,
    b: {
        c: 2
    }
};

let obj2 = {
    a: 1,
    b: {
        c: 2  
    }
};

console.log(
    isDeepStrictEqual(obj1, obj2) //=> true
)

MIMEParams

用于操作 mime 类型的字符串

import { MIMEType } from 'node:util';

const { params } = new MIMEType('text/plain;foo=0;bar=1');
for (const name of params.keys()) {
  console.log(name);
}

更多请查看官方文档

types

用于判断某个数据类型,例如:

import { types } from 'node:util'

types.isDate(new Date());  // Returns true
types.isWeakSet(new WeakSet());  // Returns true 
types.isPromise(Promise.resolve(42));  // Returns true

v15.3.0types 作为 util/types 模块暴露,更多请查看官方文档

import types from 'node:utils/types'

Released under the MIT License.