写程序时遇到 bug,最头疼的就是不知道函数是怎么一步步跑起来的。比如你点了个按钮,结果程序崩了,但你根本没动过这个功能——这时候就得靠“单步跟踪调用栈查看”来理清头绪。
什么是调用栈?
你可以把调用栈想象成一张楼梯图。每次一个函数被另一个函数调用,就往上走一级。比如 main() 调用了 loadConfig(),loadConfig() 又调用了 readFile(),那栈顶就是 readFile()。一旦出错,看一眼调用栈,就知道是哪一步踩空了。
怎么打开调用栈?
在大多数开发工具里,比如 Chrome DevTools 或 VS Code,只要设个断点,运行程序,就会自动停在那行代码上。这时候右边通常有个叫 “Call Stack” 的面板,点开就能看到当前所有嵌套调用的函数名。
单步执行,看清每一步
光看栈还不够,得一步步走。点击“逐语句”(Step Into)按钮,代码就会一行一行往下走。如果进到了某个函数内部,想跳出来,可以用“跳出”(Step Out)。这样你能清楚看到变量怎么变,流程怎么转。
举个例子,你在写一个登录验证:
function validateLogin(user) {
return checkUserExists(user) && verifyPassword(user);
}
function checkUserExists(user) {
if (!user.username) return false;
return database.has(user.username);
}
如果返回 false,到底是用户名不存在,还是密码错了?在 checkUserExists 上设断点,单步进去,看看 user.username 有没有值,数据库有没有连上,问题很快就浮出水面。
异步函数也逃不掉
有人觉得异步代码没法跟踪,其实不然。现代调试器支持 async/await 的调用链。虽然中间可能隔着事件循环,但只要你没关掉上下文,照样能在出错时看到完整的调用路径。比如 Promise.then 里报错了,调用栈会显示是从哪个 await 开始断开的。
别忘了错误堆栈信息
有些时候程序直接抛异常,根本没进调试器。这时候看控制台打印的错误信息,第一眼就要找 “at” 开头的那些行——那就是调用栈的文本版。从下往上看,找到你自己写的文件和函数,基本就能定位问题源头。
熟练使用单步跟踪和调用栈查看,等于给代码装了摄像头。再复杂的逻辑,也能一帧一帧回放,找出那个出错的瞬间。