util 是Node.js内部提供很多实用工具类型的API,能方便我们快速开发
- 由于API比较多 这里着重讲解一些常用的API,剩下的部分将以表格的形式总结在最后面
常用util的API
util.promisify
util.promisify
将一个遵循常见 Node.js 回调风格的函数(即最后一个参数是回调函数callback(err, value)
的函数)转换为返回 Promise 的函数。- 这样,可以使用现代的异步编程特性,如 async/await,来处理异步操作。
常规写法(回调函数)
- 下面这串代码是获取Node版本的常规写法
import { exec } from 'node:child_process'
exec('node -v', (err,stdout)=>{
if(err){
return err
}
console.log(stdout)
})
promise风格写法
- 一样的传入参数方式,但在接收返回结果上,从回调函数变成了.then结尾获取
- 使用util的
promisify
改为promise 风格 Promiseify 接受original
一个函数体
import { exec } from 'node:child_process'
import util from 'node:util'
const execPromise = util.promisify(exec)
//如果返回多个参数,则res就是一个对象,就需要我们通过res.xxx获取对象里的内容
execPromise('node -v').then(res=>{
console.log(res,'res')
}).catch(err=>{
console.log(err,'err')
})
实现promiseify原理
- 第一步Promiseify是返回一个新的函数
const promiseify = () => {
return () => {
}
}
- promiseify接受一个函数,并且在返回的函数才接受真正的参数,然后返回一个promise
const promiseify = (original) => {
return (...args) => {
return new Promise((resolve,reject)=>{
})
}
}
- 调用真正的函数,将参数透传给original,如果失败了就reject,如果成功了,就返回resolve,如果有多个返回一个对象。
// 定义 promiseify 函数,接收一个名为 original 的函数作为参数
const promiseify = (original) => {
// 返回一个新的函数,使用 args 参数来接收任意数量的参数
return (...args) => {
// 创建并返回一个新的 Promise 对象
return new Promise((resolve, reject) => {
// 调用原始函数,传入参数和一个新的回调函数来处理异步完成后的结果
original(...args, (err, ...values) => {
// 处理错误情况
if (err) {
// 使用 reject 函数将 Promise 的状态改为 rejected,并返回错误对象
return reject(err);
}
// 检查回调中是否有多个返回值
if (values && values.length > 1) {
// 如果有多个返回值,创建一个对象来存储这些值
let obj = {};
// 打印返回的值(主要用于调试)
console.log(values);
// 遍历 values 数组,并将每个索引和对应的值存储到 obj 对象中
for (let key in values) {
obj[key] = values[key];
}
// 使用 resolve 函数将 Promise 的状态改为 fulfilled,并返回 obj 对象
resolve(obj);
} else {
// 如果回调中只有一个返回值,直接使用 resolve 函数返回这个值
resolve(values[0]);
}
});
});
}
}
-
这样可以大致实现但是拿不到values 的key 因为 nodejs内部 没有对我们开放 这个Symbol
kCustomPromisifyArgsSymbol
-
所以输出的结果是
{ '0': 'v20.10.0\r\n', '1': '' }
正常应该是{ stdout: 'v20.10.0\n', stderr: '' }
,但我们拿不到key,就没办法做到完全一样
util.callbackify
与 util.promisify
相反,util.callbackify
将一个返回 Promise 的函数转换为遵循 Node.js 回调风格的函数。这在需要将基于 Promise 的 API 集成到仅支持回调风格的旧代码库中时非常有用。
const util = require('node:util')
//fn函数返回的结果是promise,我们要进行改写成回调风格
const fn = (type) =>{
//自己设置条件,这个需求很宽松.比如在这里我就希望type为1的情况下才是我想要的,则成功,反之失败
if(type == 1){
return Promise.resolve('success')
}else{
return Promise.reject('err')
}
}
//使用callbackify进行回调处理
const callback = util.callbackify(fn)
//Node.js 中,使用回调函数的约定是由 Node.js 的 API 设计哲学决定的.遵循了所谓的“错误优先回调”
//主要目的是确保在进行异步操作时,能够优先处理可能出现的错误
callback(1,(err,value)=> {
console.log(err,value);
})
callbackify原理
const callbackify = (fn) => {
return (...args) => {
// 考虑多个参数的情况,但是回调函数肯定在最后一个,所以使用pop把他(回调函数)取出来
let callback = args.pop()
fn(...args).then(res => {
callback(null, res)
}).catch(err => {
callback(err)
})
}
}
util.format
util.format
是一个格式化字符串的函数,类似于 C 语言中的 printf
或 Python 中的字符串格式化。它可以将多个参数组合成一个字符串,支持多种占位符,如 %s
(字符串)、%d
(数字)等。
占位符描述
%s
- 字符串%d
- 整数(使用%i
也可以得到相同结果)%f
- 浮点数%j
- JSON(如果转换失败,会替换为'[Circular]'
)%o
- 对象(带一些附加选项的详细信息)%O
- 对象(标准详细信息)%%
- 输出一个%
符号
参数 | 详细描述 |
---|---|
%s | 格式化为字符串。对于 BigInt 显示为末尾带 n ,对于 -0 显示为 0 ,普通对象使用 util.inspect() ({ depth: 0, colors: false, compact: 3 } )。 |
%d | 格式化为整数。BigInt 和 Symbol 类型除外。 |
%i | 格式化为使用 parseInt(value, 10) 的整数。BigInt 和 Symbol 类型除外。 |
%f | 格式化为使用 parseFloat(value) 的浮点数。Symbol 类型除外。 |
%j | 将参数格式化为 JSON 字符串。如果存在循环引用,则显示为 '[Circular]' 。 |
%o | 显示对象的详细多行表示,包括不可枚举属性和代理({ showHidden: true, showProxy: true } 的 util.inspect() )。 |
%O | 显示对象的详细多行表示,但不包括不可枚举属性和代理(无选项的 util.inspect() )。 |
%c | 此格式化指令用于 CSS,但在 Node.js 中被忽略。 |
%% | 输出一个百分比符号(% )。不消耗参数。 |
- 这个函数的使用方式类似于 C 语言中的
printf
或 Python 中的格式化字符串功能,让开发者能够根据指定格式来组合字符串和其他数据类型
util.format(format[, ...args])
//format 是一个字符串,包含文本以及一个或多个占位符。
//...args 是与占位符相对应的值。
使用案例
const util = require('util');
// 基础字符串格式化
console.log(util.format('%s:%s', 'name', 'Alice')); // 输出: 'name:Alice'
// 混合不同类型
console.log(util.format('My name is %s and I am %d years old.', 'Bob', 25)); // 输出: 'My name is Bob and I am 25 years old.'
// JSON 对象
console.log(util.format('User details: %j', { name: 'Carol', age: 30 })); // 输出: 'User details: {"name":"Carol","age":30}'
// 多个对象
console.log(util.format('Data: %o', { foo: 'bar' })); // 输出对象的详细信息
// 浮点数
console.log(util.format('Value: %f', 3.14159265)); // 输出: 'Value: 3.14159265'
// 显示百分比
console.log(util.format('100%% Complete')); // 输出: '100% Complete'