nodejs 第十八章 util

265 阅读5分钟

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')
})

image-20240414121235046

实现promiseify原理

  1. 第一步Promiseify是返回一个新的函数
const promiseify = () => {
   return () => {

  }
}
  1. promiseify接受一个函数,并且在返回的函数才接受真正的参数,然后返回一个promise
const promiseify = (original) => {
   return (...args) => {
     return new Promise((resolve,reject)=>{
        
     })
  }
}
  1. 调用真正的函数,将参数透传给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]);
                }
            });
        });
    }
}

image-20240414121511314

  • 这样可以大致实现但是拿不到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);
})

image-20240414123607283

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格式化为整数。BigIntSymbol 类型除外。
%i格式化为使用 parseInt(value, 10) 的整数。BigIntSymbol 类型除外。
%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'