同步异常由调用栈即时承载,引擎立即暂停执行并逐层查找try...catch;未捕获则终止当前宏任务,触发全局错误监听,且不进入任何任务队列。

同步异常直接由调用栈承载,一旦抛出,JavaScript 引擎立即暂停当前执行路径,沿着调用栈逐层向上查找最近的 try...catch 块;没被捕获就终止当前宏任务,并触发全局错误监听(如 window.onerror 或 process.on('uncaughtException'))。
同步异常发生在调用栈内
同步代码执行时,每层函数调用都会压入调用栈。异常发生瞬间,引擎记录当前栈帧状态,包括函数名、行号、作用域链等信息。这个“快照”就是回溯的基础。
- 错误对象(如
Error)自带stack字符串,内容正是从当前帧开始,逆序列出所有调用层级 - 栈顶函数出错 → 引擎检查该函数是否有
catch→ 没有则弹出该帧,跳到上一帧继续查找 - 若整个调用栈清空仍未捕获,异常穿透至事件循环层面,当前宏任务宣告失败
它不进入任何任务队列
同步异常和异步错误处理机制完全不同:它不会被推入微任务或宏任务队列,也不会等待事件循环调度。它是即时、阻断式的,发生在调用栈尚在运行的过程中。
-
Promise.reject()或throw在then回调里 → 属于微任务内抛出 → 触发Promise.catch或未捕获 Promise rejection 警告 - 但
throw new Error('boom')写在普通函数体第一行 → 立即中断执行,不经过队列,不依赖 Event Loop - 也就是说:只要没被
try包住,同步异常会让当前这一轮 JS 执行彻底停住,后续同层代码不再运行
回溯信息依赖执行上下文
stack 属性的内容真实反映函数调用链,但前提是调用过程没被优化抹除(如尾调用优化在严格模式下可能省略中间帧)。开发中常见影响回溯清晰度的情况:
- 箭头函数、匿名函数会让堆栈显示为
anonymous,建议命名关键函数便于定位 - 打包工具(如 Webpack)开启 source map 后,浏览器能将压缩后位置映射回原始源码行
- Node.js 中可通过
--trace-warnings查看未处理 Promise rejection 的完整调用路径
与异步错误的关键区别
异步错误(比如 setTimeout 回调里抛错)发生在新的宏任务中,它的调用栈只包含那个回调本身,原始调用链已不存在;而同步异常的调用栈保留了完整的“谁调用了谁”的路径。
- 这意味着:你能从同步错误的
stack看出是哪个业务模块层层调用导致的问题 - 但异步错误只能看到“定时器回调抛错了”,无法自动关联到最初设置定时器的那一行
- 所以对关键异步入口(如 API 请求封装),常需手动在
catch中打点或附加上下文日志











