0

0

Console 模块解读及简单实现

絕刀狂花

絕刀狂花

发布时间:2025-07-31 08:22:28

|

797人浏览过

|

来源于php中文网

原创

console 模块解读及简单实现console 模块提供了简单的调试功能,这在一些测试调试中常是最方便且使用最多的工具。它类似于浏览器中的 console,但有一个关键区别:在浏览器中它是同步的,而在 node.js 中,它是否同步或异步取决于操作系统和输出流类型。

本文参考了官方源码,实现了一个简化的 Console 模块版本,介绍了其基本用法,并提出了常见的问题,供大家学习和参考。具体内容请详见下文。

作者简介:五月君,Node.js 开发者,热爱技术并乐于分享的 90 后青年,公众号「Nodejs技术栈」的作者,GitHub 开源项目维护者,网址为 https://www.php.cn/link/d2450555f921f45a0c0bf6f41bd95a3d

快速导航

  • Logger 模块实现
    • 实现步骤
    • 创建 logger.js 文件
  • Logger 模块基本使用
    • 日志输出至终端
      • log、info、error、warn、clear
    • 日志输出至文件
    • trace 打印错误堆栈
    • dir 显示一个对象的所有属性和方法
    • time 和 timeEnd 计算程序执行消耗时间
  • 面试指南
    • console 是同步的还是异步的?,参考:#
    • 如何实现一个 console.log?,参考:#
    • 为什么 console.log() 执行完后就退出?,参考:#

Logger 模块实现步骤

  • 初始化 Logger 对象
  • 对参数进行检验,当前对象是否为 Logger 实例,是否为一个可写流实例
  • 为 Logger 对象定义 stdout,stderr 等属性
  • 将原型方法上的属性绑定到 Logger 实例上
  • 实现 log、error、warning、trace、clear 等方法

创建 logger.js 文件 以下是 logger.js 文件的代码:

const util = require('util');

/**

  • 初始化 Logger 对象
  • @param {*} stdout
  • @param {} stderr / function Logger(stdout, stderr) { // 检查当前对象是否为 Logger 实例 if (!(this instanceof Logger)) { return new Logger(stdout, stderr); } // 检查是否是一个可写流实例 if (!stdout || !(stdout.write instanceof Function)) { throw new Error('Logger expects a writable stream instance'); } // 如果 stderr 未指定,使用 stdout if (!stderr) { stderr = stdout; } // 设置 JavaScript 对象的属性 let props = { writable: true, // 对象属性是否可修改,false 为不可修改,默认值为 true enumerable: false, // 对象属性是否可通过 for-in 循环,false 为不可循环,默认值为 true configurable: false, // 能否使用 delete、能否修改属性特性、或能否修改访问器属性,false 为不可重新定义,默认值为 true }; // Logger 对象定义 _stdout 属性 Object.defineProperty(this, '_stdout', Object.assign(props, { value: stdout, })); // Logger 对象定义 _stderr 属性 Object.defineProperty(this, '_stderr', Object.assign(props, { value: stderr, })); // Logger 对象定义 _times 属性 Object.defineProperty(this, '_times', Object.assign(props, { value: new Map(), })); // 将原型方法上的属性绑定到 Logger 实例上 const keys = Object.keys(Logger.prototype); for (let k in keys) { this[keys[k]] = this[keys[k]].bind(this); } }

// 定义原型 Logger 的 log 方法 Logger.prototype.log = function() { this._stdout.write(util.format.apply(this, arguments) + '\n'); };

Logger.prototype.info = Logger.prototype.log;

// 定义原型 Logger 的 warn 方法 Logger.prototype.warn = function() { this._stderr.write(util.format.apply(this, arguments) + \n); };

Logger.prototype.error = Logger.prototype.warn;

微尔企业网站管理系统1.75 build build 090709
微尔企业网站管理系统1.75 build build 090709

系统功能介绍 1 包含企业网站所必备的功能:企业信息、产品管理、人才招聘、新闻资讯、企业图片、以及视频下载等模块2 由于是从CMS系统的基础上开发而成,因此相对于一些其他的企业网站管理系统,本系统具备更强的可扩展能力,可以胜任从小型工作室到大中型企业网上门户等各种不同规模网站的需求。3 后台管理与模板完全分离,并具备非常灵活的标签技术,可以实现无限制个性化的界面定制4 操作简单,利用已经制作好的模

下载

// 返回当前调用堆栈信息 Logger.prototype.trace = function trace(...args) { const err = { name: 'Trace', message: util.format.apply(null, args) }; // 源自 V8 引擎的 Stack Trace API https://www.php.cn/link/a41c3b5da4b5a60a165094e92c46da60 Error.captureStackTrace(err, trace); this.error(err.stack); };

// 清除控制台信息 Logger.prototype.clear = function() { // 如果 stdout 输出是一个控制台,进行 clear 否则不进行处理 if (this._stdout.isTTY) { const { cursorTo, clearScreenDown } = require('readline'); cursorTo(this._stdout, 0, 0); // 移动光标到给定的 TTY stream 中指定的位置。 clearScreenDown(this._stdout); // 方法会从光标的当前位置向下清除给定的 TTY 流 } };

// 直接输出某个对象 Logger.prototype.dir = function(object, options) { options = Object.assign({ customInspect: false }, options); /**

  • util.inspect(object,[showHidden],[depth],[colors]) 是一个将任意对象转换为字符串的方法,通常用于调试和错误的输出。
  • showhidden - 是一个可选参数,如果值为 true,将会输出更多隐藏信息。
  • depth - 表示最大递归的层数。如果对象很复杂,可以指定层数控制输出信息的多少。
  • 如果不指定 depth, 默认会递归 3 层,指定为 null 表示不限递归层数完整遍历对象。
  • 如果 color = true,输出格式将会以 ansi 颜色编码,通常用于在终端显示更漂亮的效果。 */ this._stdout.write(util.inspect(object, options) + '\n'); };

// 计时器开始时间 Logger.prototype.time = function(label) { // process.hrtime() 方法返回当前时间以 [seconds, nanoseconds] tuple Array 表示的高精度解析值, nanoseconds 是当前时间无法使用秒的精度表示的剩余部分。 this._times.set(label, process.hrtime()); };

// 计时器结束时间 Logger.prototype.timeEnd = function(label) { const time = this._times.get(label); if (!time) { process.emitWarning(No such label '${label}' for console.timeEnd()); return; } const duration = process.hrtime(time); const ms = duration[0] 1000 + duration[1] / 1e6; // 1e6 = 1000000.0 1e6 表示 110^6 this.log('%s: %sms', label, ms.toFixed(3)); this._times.delete(label); };

module.exports = new Logger(process.stdout, process.stderr); module.exports.Logger = Logger;

Logger 模块基本使用

日志输出至终端 无特殊说明,日志都是默认打印到控制台,在一些代码调试中也是用的最多的。

const logger = require('logger');
logger.log('hello world'); // 普通日志打印
logger.info('hello world'); // 等同于 logger.log
logger.error('hello world'); // 错误日志打印
logger.warn('hello world'); // 等同于 logger.error
logger.clear(); // 清除控制台信息

日志输出至文件 定义要输出的日志文件,实例化我们自定义的 Logger 对象。

const fs = require('fs');
const output = fs.createWriteStream('./stdout.txt');
const errorOutput = fs.createWriteStream('./stderr.txt');
const { Logger } = require('./logger');
const logger = new Logger(output, errorOutput);
logger.info('hello world!'); // 内容输出到 stdout.txt 文件
logger.error('错误日志记录'); // 内容输出到 stderr.txt 文件

版本问题 将日志信息打印到本地指定文件,这里要注意版本问题,以下代码示例在 Node.js v10.x 以下版本可以运行,但在 Node.js v10.x 及以上版本可能会报错,具体原因请参见 https://www.php.cn/link/d3416acbe6cd441c5fea6bf3a9816cd9

TypeError: Console expects a writable stream instance
at new Console (console.js:35:11)
at Object. (/Users/ryzokuken/Code/temp/node/console/21366.js:11:16)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
at startup (bootstrap_node.js:188:16)
at bootstrap_node.js:609:3

trace 打印错误堆栈

logger.trace('测试错误');

输出如下:

Trace: 测试错误
at Object. (/Users/qufei/Documents/mycode/Summarize/test/console-test.js:7:8)
at Module._compile (module.js:624:30)
at Object.Module._extensions..js (module.js:635:10)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
at Function.Module.runMain (module.js:665:10)
at startup (bootstrap_node.js:201:16)
at bootstrap_node.js:626:3

dir 显示一个对象的所有属性和方法 depth - 表示最大递归的层数。如果对象很复杂,可以指定层数控制输出信息的多少。

const family = {
name: 'Jack',
brother: {
hobby: ['篮球', '足球']
}
};
logger.dir(family, {depth: 3});
// { name: 'Jack', brother: { hobby: [ '篮球', '足球' ] } }

计算程序执行消耗时间 logger.time 和 logger.timeEnd 用来测量一个 JavaScript 脚本程序执行消耗的时间,单位是毫秒。

// 启动计时器
logger.time('计时器');
// 中间写一些测试代码
for (let i = 0; i < 1000000; i++) {}
// 结束计时器
logger.timeEnd('计时器');
// 计时器: 12.345ms

面试指南

console 是同步的还是异步的? console 既不是总是同步的,也不是总是异步的。是否为同步取决于链接的是什么流以及操作系统是 Windows 还是 POSIX:

注意: 同步写将会阻塞事件循环直到写完成。有时可能一瞬间就能写到一个文件,但当系统处于高负载时,管道的接收端可能不会被读取、缓慢的终端或文件系统,因为事件循环被阻塞的足够频繁且足够长的时间,这些可能会给系统性能带来消极的影响。当你向一个交互终端会话写时这可能不是个问题,但当生产日志到进程的输出流时要特别留心。

  • 文件(Files): Windows 和 POSIX 平台下都是同步
  • 终端(TTYs): 在 Windows 平台下同步,在 POSIX 平台下异步
  • 管道(Pipes): 在 Windows 平台下同步,在 POSIX 平台下异步

如何实现一个 console.log? 实现 console.log 在控制台打印,利用 process.stdout 将输入流数据输出到输出流(即输出到终端),一个简单的例子输出 hello world。

process.stdout.write('hello world!' + '\n');

为什么 console.log() 执行完后就退出? 这个问题第一次看到是来自于朴灵大神的一次演讲,涉及到 EventLoop 的执行机制,一旦产生事件循环,就会产生一个 While(true) 的死循环,例如定时器 setInterval,但是 console.log 它没有产生 watch、handlers 在事件循环中执行了一次就退出了。同时另一个疑问开启一个 http server 为什么进程没有退出?参考下文章 Node.js 为什么进程没有 exit?。

参考资料

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

98

2023.09.25

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

301

2023.10.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

399

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

575

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

399

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

575

2023.08.10

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

516

2023.06.20

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

54

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 10万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2万人学习

Node.js-前端工程化必学
Node.js-前端工程化必学

共19课时 | 3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号