查看: 246|回复: 3

Node.js util模块promisify与inspect用法

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
一、util 模块在 Node.js 中的定位

util 是 Node.js 的内置核心模块,定位是“实用工具库”,用来弥补 JavaScript 原生能力的不足,把类型判断、调试输出、回调与 Promise 互转、原型继承等常见编程任务封装成开箱即用的函数。在 Node.js 早期版本中,util.inherits、util.inspect 这类能力就属于该模块,后来部分功能被整合到其他模块中,但 util 依旧保留了相当多仍在日常开发中高频使用的工具函数。

使用时无需安装,直接引入即可:
  1. const util = require('util');
复制代码

按用途划分,util 模块的常用能力可以归为以下几类:


  • 类型检查:util.types.*,用于精确判断数据类型
  • 字符串格式化:util.format()、util.inspect()
  • 回调与 Promise 互转:util.promisify()、util.callbackify()
  • 原型继承:util.inherits()
  • 调试输出:util.debuglog()、util.inspect()
  • 废弃标记:util.deprecate()


二、类型检查:util.types 比 typeof / instanceof 更可靠

util.types 提供一组精确的类型判定方法,避免 typeof 对部分类型判断不准确、instanceof 受原型链影响的问题。下面示例演示 ArrayBuffer 与 Date 的判断:
  1. const util = require('util');
  2. // ArrayBuffer 检查
  3. const arrBuffer = new ArrayBuffer(8);
  4. console.log(util.types.isArrayBuffer(arrBuffer)); // true
  5. console.log(util.types.isArrayBuffer([]));        // false
  6. // Date 检查
  7. console.log(util.types.isDate(new Date()));        // true
  8. console.log(util.types.isDate('2023-01-01'));      // false
复制代码

常用判定方法包括:isArrayBuffer、isAsyncFunction、isDate、isMap、isSet、isRegExp、isPromise、isTypedArray,分别用于判断对应类型的实例,写法统一,参数均为待检测的 value。

三、字符串格式化:util.format

util.format 的行为类似 C 语言的 printf,通过占位符把参数拼进模板字符串。支持的占位符中,%s 对应字符串,%d 对应数字,%j 对应 JSON 序列化后的对象:
  1. const util = require('util');
  2. const name = 'John';
  3. const age = 30;
  4. console.log(util.format('My name is %s and I am %d years old', name, age));
  5. // 输出: My name is John and I am 30 years old
  6. console.log(util.format('%s - %d - %j', 'string', 123, { key: 'value' }));
  7. // 输出: string - 123 - {"key":"value"}
复制代码

当需要在日志或错误信息中拼装结构化数据时,%j 比手工 JSON.stringify 更省事。

四、对象检查:util.inspect 与常用选项

util.inspect 返回对象的字符串表示,主要用于调试输出,相比直接 console.log 能更完整地呈嵌套结构与特殊类型。可配置的常用选项如下:


  • depth:递归深度,null 表示无限层级
  • colors:是否使用颜色输出
  • showHidden:是否显示不可枚举属性
  • compact:是否压缩输出


基础用法:
  1. const util = require('util');
  2. const obj = {
  3.     name: 'Alice',
  4.     details: {
  5.         age: 25,
  6.         hobbies: ['reading', 'coding']
  7.     }
  8. };
  9. console.log(util.inspect(obj, { depth: 2, colors: true }));
复制代码

处理包含正则、日期、函数等成员的复杂对象时,把 depth 设为 null 并打开 showHidden 可以看到更完整的信息:
  1. const util = require('util');
  2. const complexObj = {
  3.     date: new Date(),
  4.     regex: /test/g,
  5.     nested: {
  6.         array: [1, 2, 3],
  7.         fn: function() {}
  8.     }
  9. };
  10. console.log(util.inspect(complexObj, {
  11.     showHidden: true,
  12.     depth: null,
  13.     colors: true
  14. }));
复制代码

五、回调与 Promise 的互相转换

util.promisify 用于把遵循 Node.js error-first 回调风格的函数转换为返回 Promise 的函数,从而可以直接配合 async/await 使用。以 fs.readFile 为例:
  1. const util = require('util');
  2. const fs = require('fs');
  3. const readFile = util.promisify(fs.readFile);
  4. async function readConfig() {
  5.     try {
  6.         const data = await readFile('config.json', 'utf8');
  7.         console.log(data);
  8.     } catch (err) {
  9.         console.error('Error reading file:', err);
  10.     }
  11. }
  12. readConfig();
复制代码

util.callbackify 则是反向操作,把返回 Promise 的函数转换为回调风格函数,回调的第一个参数是错误:
  1. const util = require('util');
  2. async function asyncFunc() {
  3.     return 'Hello World';
  4. }
  5. const callbackFunc = util.callbackify(asyncFunc);
  6. callbackFunc((err, result) => {
  7.     if (err) throw err;
  8.     console.log(result); // Hello World
  9. });
复制代码

这一对 API 的典型价值是把沉淀下来的旧回调代码接入新的 async/await 调用链,而不必重写内部实现。

六、原型继承:util.inherits

util.inherits 实现 ES5 风格的原型继承,把子构造函数与父构造函数关联起来:
  1. const util = require('util');
  2. function Animal(name) {
  3.     this.name = name;
  4. }
  5. Animal.prototype.speak = function() {
  6.     console.log(this.name + ' makes a noise.');
  7. };
  8. function Dog(name) {
  9.     Animal.call(this, name);
  10. }
  11. util.inherits(Dog, Animal);
  12. Dog.prototype.speak = function() {
  13.     console.log(this.name + ' barks.');
  14. };
  15. const d = new Dog('Rex');
  16. d.speak(); // Rex barks.
复制代码

需要注意,在 ES6 及之后的代码中,官方建议直接使用 class 与 extends 关键字替代 util.inherits,后者主要出现在需要维护的老代码里。

七、废弃标记:util.deprecate

util.deprecate 包装一个函数,使其被调用时发出弃用警告,适合在库升级时平滑提示调用方:
  1. const util = require('util');
  2. const oldFunction = util.deprecate(
  3.     () => { console.log('This function is deprecated'); },
  4.     'oldFunction is deprecated. Use newFunction instead.'
  5. );
  6. oldFunction();
  7. // 输出: This function is deprecated
  8. // 同时 Node.js 会显示弃用警告
复制代码

八、自定义对象的 inspect 输出

在类中实现 [util.inspect.custom] 方法,可以改变 util.inspect 对该类实例的输出内容,便于调试时只看关键字段:
  1. const util = require('util');
  2. class CustomObject {
  3.     constructor(value) {
  4.         this.value = value;
  5.     }
  6.     [util.inspect.custom](depth, options) {
  7.         return `CustomObject: ${this.value}`;
  8.     }
  9. }
  10. const obj = new CustomObject('test');
  11. console.log(util.inspect(obj)); // CustomObject: test
复制代码

九、常用方法及引入版本


  • util.callbackify(original):Promise 转回调风格函数,8.2.0
  • util.debuglog(section):条件调试日志,0.11.3
  • util.deprecate(fn, msg[, code]):标记废弃函数,0.8.0
  • util.format(format[, ...args]):格式化字符串,0.5.3
  • util.formatWithOptions(inspectOptions, format[, ...args]):带选项的格式化,10.0.0
  • util.getSystemErrorName(err):获取系统错误名称,9.7.0
  • util.inherits(constructor, superConstructor):原型继承,0.3.0
  • util.inspect(object[, options]):对象字符串表示,0.3.0
  • util.isDeepStrictEqual(val1, val2):深度严格相等比较,9.0.0
  • util.promisify(original):回调转 Promise,8.0.0
  • util.stripVTControlCharacters(str):剥离 ANSI 转义码,16.11.0
  • util.parseArgs([config]):命令行参数解析,18.3.0
  • util.types:类型检查工具对象,10.0.0


对照版本号可以在维护多版本 Node.js 项目时快速判断某个 API 是否可用,例如需要兼容 8.0.0 以下环境时就不能直接依赖 promisify。

十、使用注意事项


  • 性能:util.inspect 处理大型对象或无限深度时有明显开销,生产环境日志中应谨慎使用,避免在高频路径上反复序列化。
  • API 稳定性:部分 util 方法在文档中仍被标记为实验性功能,升级 Node.js 大版本前应确认状态。
  • 现代替代:util.inherits 可用 class/extends 替代,新代码不建议继续引入。
  • 错误处理:使用 promisify 后必须正确处理 Promise 拒绝,否则容易产生未捕获的 Promise rejection;callbackify 场景下则要检查回调首个 err 参数。


十一、小结

util 模块覆盖了类型判断(util.types)、格式化与调试(util.format、util.inspect)、回调与 Promise 互转(util.promisify、util.callbackify)、继承(util.inherits)和废弃标记(util.deprecate)等场景。其中 promisify 是日常开发中使用频率最高的方法,它能把大量基于回调的 Node.js 核心模块函数转换为返回 Promise 的函数,与 async/await 配合顺畅;而 inspect 的自定义输出能力则能让复杂对象的调试信息更可控。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Node.js util模块promisify与inspect用法

楼主这篇整理得挺系统的,从定位、类型检查到 format、inspect、promisify 都覆盖到了,示例也都能直接跑,对刚接触 util 的同学很友好。提几个小点供参考: 一是帖子末尾好像截断了,callbackify 那段只贴到 “async f” 就没了,方便的话可以补完整,正好和 promisify 对照着看更清楚。 二是 promisify 那边可以顺带提醒一句:它只适用于 error-first 回调风格的函数,像 fs.exists 这种回调不按这个约定的就不能直接转;如果自己封装的函数想控制 promisify 后的行为,可以用 util.promisify.custom 这个符号挂一个自定义实现,这个在实际项目里挺常用的。 三是 inspect 的 depth 默认值是 2,很多人调试嵌套对象时发现打印出来是 就是这个原因,设成 null 才无限展开。另外 colors 打开后输出里会带 ANSI 转义字符,如果是写日志文件而不是打到终端,最好关掉,不然文件里会多一堆乱码字符。 四是 format 的 %j 遇到循环引用会抛错,如果日志里可能塞进带循环结构的对象,可以先处理一下再用,或者直接用 inspect 更稳妥。 整体内容质量不错,期待把 callbackify 部分补齐。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Node.js util模块promisify与inspect用法

这篇整理得挺清楚的,按类型检查、格式化、inspect、Promise 与回调互转来分类,示例也比较直观。inspect 里 depth、colors、showHidden 这些常用选项点得很实用,promisify 配合 fs.readFile 和 async/await 的写法也很典型。 不过看到最后 callbackify 的示例停在“async f”这里,应该是帖子内容没贴完整,后面如果能补上完整示例会更好理解。整体上作为 util 模块的入门和速查内容挺有帮助的。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Node.js util模块promisify与inspect用法

这篇整理得挺系统,把 util 模块里比较常用的几个方向都覆盖到了,尤其是类型检查、格式化、inspect 和 promisify 这几块,日常写 Node.js 脚本时确实很容易用到。 我比较认同把 util.types 单独拿出来讲,因为 typeof 和 instanceof 在有些场景下判断不够精确,用 util.types.isDate、isMap、isPromise 这类方法会稳妥很多。util.format 的 %j 占位符也很实用,拼日志时能少写不少 JSON.stringify。 util.inspect 部分给出的 depth 和 showHidden 示例挺直观,调试复杂对象时比直接 console.log 更容易看到嵌套内容。promisify 配合 async/await 的写法也很清楚,尤其适合把 fs.readFile 这种 error-first 回调风格的老 API 包一层。 整体看下来内容比较适合作为 util 模块的入门和速查。后面如果继续补充,可以再提一下 promisify 对回调风格的要求,以及 inspect 主要用于调试展示、不适合当作数据序列化输出,这样边界会更清楚。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-11-6 06:34 , Processed in 0.021512 second(s), 28 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部