一、Node.js Console是什么
Node.js的console是一个内置全局对象,提供向终端输出调试信息、日志、错误和警告的方法。它基于两个标准流工作:
-
stdout(标准输出流):常规日志走这里;
-
stderr(标准错误流):错误和警告走这里。
这个区分很关键。很多人以为console.error()和console.log()只是“打印内容不同”,实际上它们写入的流不同。在终端里两者看起来差不多,但一旦做输出重定向,差异立刻显现:nodeapp.js>out.log只会把stdout的内容写进文件,stderr仍然打在屏幕上。生产环境做日志采集时,这个区别直接影响你能否把错误单独捞出来。
Console模块提供的方法和浏览器里的console类似,但Node.js环境下有自己的行为特征,比如console.warn()在Node.js中写入的是stderr,而不是浏览器里那种带黄颜色背景的样式化输出。
二、为什么项目里离不开Console
Console在开发中的角色可以归为四类:
日志记录:把事件、警告、错误写下来,便于回溯。
调试:快速查看变量值、执行路径、错误堆栈。
开发与测试:即时验证代码输出,不用反复启停服务。
性能监控:用计时方法测量某段代码或某个函数的执行耗时。
我自己的习惯是:开发阶段用console做即时反馈,上线后把关键日志接入结构化日志库。Console不是“低级工具”,它是排查问题的第一入口。
三、三个基础方法:log、error、warn
3.1console.log()
最常用的输出方法,把消息打印到stdout。
console.log('代码号学习编程');
输出:
代码号学习编程
它支持多个参数、格式化占位符,也能直接打印对象。
const user = { name: 'Alan', role: 'admin' };
console.log('当前用户:', user);
3.2console.error()
把错误信息写入stderr。
console.error('数据库连接失败');
输出:
数据库连接失败
在终端里,很多环境会把stderr的内容用红色显示,方便和普通日志区分。做异常捕获时,console.error()是标配:
try {
JSON.parse('{bad json}');
} catch (err) {
console.error('解析失败:', err.message);
}
3.3console.warn()
输出警告信息,在Node.js中同样写入stderr。
const name = 'John';
console.warn(`注意,${name},当前接口已废弃`);
输出:
注意,John,当前接口已废弃
踩坑经历:早期做日志重定向时,我把console.warn()当成普通日志,结果警告信息全跑到stderr里,采集脚本只抓stdout,警告全丢了。后来统一约定:需要进入常规日志文件的用console.log(),需要单独监控的警告和错误走console.warn()/console.error()。
四、进阶方法:info、table、time
4.1console.info()
console.info()和console.log()行为基本一致,向stdout输出一行消息。区别更多是语义上的:用它表达“信息性提示”。
console.info('服务启动完成');
console.info('当前处理条数: %d', 39);
输出:
服务启动完成
当前处理条数: 39
%d是格式化占位符,会把后面的数值插入到消息里。常用占位符还有%s(字符串)、%j(JSON)、%o(对象)。
4.2console.table()
把数组或对象以表格形式打印,查看结构化数据时比console.log()直观得多。
console.table([
{ q: 3, r: 4 },
{ q: 8, r: 9, s: 'y' }
]);
输出是一张带索引和列名的表格。
第二个参数可以指定只显示哪些列:
console.table(
[
{ q: 3, r: 4 },
{ q: 3, r: 7, s: 'y' }
],
['q', 'r']
);
这样只输出q和r两列,s被过滤掉。
项目反思:排查接口返回的数组数据时,我以前用console.log(JSON.stringify(data,null,2)),输出又长又难对齐。换成console.table(data)后,字段对齐、行号清晰,比对几条记录的差异快很多。如果数据嵌套层级深,console.table()对嵌套对象的展示有限,这时还是得回到console.log()或console.dir()。
4.3console.time()与console.timeEnd()
用来测量代码执行耗时。
function sumCount() {
let sum = 0;
for (let num = 1; num < 100000; num++) {
sum += num;
}
return sum;
}
console.time('timetaken');
sumCount();
console.timeEnd('timetaken');
输出:
timetaken: 1.091ms
console.time(label)启动一个带标签的计时器,console.timeEnd(label)停止并输出耗时,单位是毫秒。同一个程序里可以用不同标签管理多个计时器。
个人建议:计时标签成对出现,别只写console.time()忘了console.timeEnd(),否则计时器不会输出结果。单次耗时受系统负载影响,别拿一次结果当性能结论,多跑几次看趋势更靠谱。
五、log、warn、error三者对比
| 特性 | console.log() | console.warn() | console.error() |
|---|---|---|---|
| 定义 | 打印消息、变量、表达式 | 输出警告信息 | 输出错误信息 |
| 用途 | 常规日志记录 | 标记非阻塞、非关键问题 | 操作失败或抛出异常时使用 |
| 输出流 | process.stdout | process.stderr | process.stderr |
| 典型场景 | 用户登录成功日志 | 接口版本废弃提醒 | 支付处理失败 |
用一张表把差异固定下来,团队协作时不容易混用。
为什么区分warn和error:两者都写stderr,但语义不同。警告是“还能跑,但该修”,错误是“已经出问题了”。日志系统按级别过滤时,这个区分决定了哪些信息会被优先处理。
六、项目实例:一个简单的请求日志封装
下面这段代码用console的几个方法组合出一个轻量日志工具,适合小型项目或脚本。
function logRequest(method, url, status, duration) {
const msg = `${method} ${url} - ${status} - ${duration}ms`;
if (status >= 500) {
console.error(msg);
} else if (status >= 400) {
console.warn(msg);
} else {
console.log(msg);
}
}
logRequest('GET', '/api/users', 200, 45);
logRequest('POST', '/api/orders', 404, 12);
logRequest('GET', '/api/pay', 500, 230);
输出大致为:
GET /api/users - 200 - 45ms
POST /api/orders - 404 - 12ms
GET /api/pay - 500 - 230ms
后两条分别走console.warn()和console.error(),写入stderr。这样在终端里能一眼看出哪些请求出了问题,重定向日志时也能分开处理。
如果想看结构化数据,把状态码统计换成表格:
const stats = [
{ path: '/api/users', count: 120, errors: 0 },
{ path: '/api/orders', count: 80, errors: 3 },
{ path: '/api/pay', count: 50, errors: 5 }
];
console.table(stats);
排查哪个接口错误多,一眼就能定位。
七、本节课程知识要点
-
console是Node.js内置全局对象,基于stdout和stderr两个流工作。
-
console.log()写stdout,适合常规日志。 -
console.error()和console.warn()写stderr,分别对应错误和警告。 -
console.info()与console.log()行为接近,语义上表示信息性输出。 -
console.table()适合展示数组或对象,第二个参数可筛选列。 -
console.time()与console.timeEnd()成对使用,测量代码耗时,标签要一致。 -
重定向输出时,stdout和stderr分开处理,别把警告和错误混进普通日志文件。
-
生产环境的关键日志建议接入结构化日志库,console更适合开发调试和轻量脚本。