Node 中的栈追踪
当Node程序的执行出现错误时,发生错误的位置以及产生错误的方法会作为最终的输出内容记录到STDERR(标准错误输出)中。
这就是栈追踪。默认情况下,Node 的Javascript V8引擎保存10帧的记录。
但是,很多情况下,我们需要更多的帧数才能从堆栈上下文中找到产生错误的根本原因。另一方面,栈追踪越大,我们就需要消耗更多的CPU进程和内存,去保持栈追踪(stack trace)。
我们先简单搭建一个应用。
mkdir app
cd app & npm init -y & npm install express
进入app文件夹
touch index.js routes.js content.js
index.js文件中内容如下:
const express = require('express')
const routes = require('./routes')
const app = express()
app.use(routes)
app.listen(3000)
routes.js 中内容如下:
const content = require('./content')
const { Router } = require('express')
const router = new Router()
router.get('/', (req, res) => {
res.send(content())
})
module.exports = router
content.js中内容如下:
function content(opts, c = 20) {
return --c ? content(opts, c) : opts.ohoh
}
module.exports = content
然后我们启动程序:
node index.js
浏览器中打开localhost:3000,我们可以在终端窗口中看到栈追踪记录。
这个记录本质上是一个递归调用。
这个错误消息非常明显,【cannot read property 'ohoh' of undefined】。
但是因为我们的堆栈被限制为10帧,所以我们无法看到最初调用函数第一次迭代的内容。
通过使用 --stack-trace-limit 标识,我们可以解决这个问题。
node --stack-trace-limit=21 index.js
这时候,我们可以看到错误出现在app/routes.js的第7行第12列。
routes.js的第7行内容如下:
res.send(content())
调用content方法时参数为空,所以就报错了。
stack-trace-limit标识通知V8引擎在每个事件循环的tick中维护更多的stack,当程序出现错误时,生成一个可以回溯到最初调用函数的追踪栈。
然后我们就可以通过这个栈信息查找出现错误的原因。
我们可以在进程中设置堆栈限制吗?
如果我们希望在生产环境和开发环境中使用不同的堆栈跟踪限制呢?
我们可以跟踪同步函数调用吗?
有可能有更好看的堆栈跟踪吗?
开发环境中,我们大多希望可以得到更多的上下文信息。
我们可以在index.js顶部添加一些内容:
if(process.env.NODE_ENV !== 'production'){
Error.stackTraceLimit = Infinity
}
运行并访问程序
node index.js
这时候栈追踪的数量就没有限制了。
我们可以把追踪栈的外观处理的更加人性化。
这需要我们安装cute-stack包。
npm install --save cute-stack
然后在index.js中引入它:
require('cute-stack')()
运行程序
node --stack-track-limit=21 index.js
然后我们可以看到格式化后的堆栈信息:
cute-stack利用了专有的API。Error.prepareStackTrace,它可以被指定为接收错误和堆栈输入的函数。然后,该函数可以处理堆栈并返回一个字符串。
JavaScript的异步特性会影响堆栈跟踪的工作方式。在JavaScript中,每个tick(每次JavaScript事件循环)都有一个新堆栈。
我们将content.js修改一下:
function content(opts, c = 20) {
// return --c ? content(opts, c) : opts.ohoh
function produce (cb){
if(--c) setTimeout(produce,10,cb)
cb(null,opts.ohoh)
}
}
module.exports = content
同时修改下routes.js:
function content(opts, c = 20) {
// return --c ? content(opts, c) : opts.ohoh
function produce (cb){
if(--c) setTimeout(produce,10,cb)
cb(null,opts.ohoh)
}
}
module.exports = content
然后运行程序。
我们可以看到按照超时时间降序排列的栈追踪信息。
我们可以通过【longjohn】模块获得异步栈追踪信息。
npm install --save-dev longjohn
然后修改index.js
// require('cute-stack')()
const express = require('express')
const routes = require('./routes')
const app = express()
if (process.env.NODE_ENV !== 'production') {
// Error.stackTraceLimit = Infinity
require('longjohn')
}
app.use(routes)
app.listen(3000)
运行程序。
这时候我们可以看到原始栈追踪的信息后面跟着一条虚线,虚线后面是之前的tick。
本文分享自 JavaScript高级程序设计 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!