JavaScript 代码不能被阻断的稳定性建设
本文探讨 JavaScript 代码因异常导致后续执行被阻断的风险,重点分析 try-catch 的使用局限。指出 throw 语句会阻断代码且仅限在 try 块内使用,异步代码无法被同步 try-catch 捕获。详细对比了 require 与 import() 的错误处理差异,强调 import() 作为 Promise 需采用链式 catch 方式,并提醒注意错误上报机制的完整性。
背景
在 JavaScript 开发中,确保代码的稳定性至关重要,核心原则是防止单个错误导致整个脚本执行流程被阻断。
JavaScript 代码可能因各种未预见的错误而中断,进而导致后续所有代码无法执行,这直接威胁到线上环境的稳定性。
最常见的 JavaScript 被阻断的情况
console.log(111)
// 预期 a = {}
// 结果
a = undefined
a.a = 1
console.log(222) // js代码不能执行到这一行
以下代码明显会抛出错误,错误始于 a.a = 1 这一行,导致后续的 JavaScript 代码执行流被阻断,console.log(222) 因此无法打印输出。
解决办法
- 解决思路相对直接,即使用 try...catch... 语句块来捕获可能发生的错误。
console.log(111)
try {
// 预期 a = {}
// 结果
a = undefined
a.a = 1
} catch (e) {
console.error(e)
}
console.log(222) // js代码可以执行到这一行
容易被我们忽视的点
1. 没考虑到错误上报
- 上述示例代码未包含错误上报逻辑。当错误发生时,外部监控系统(即使接入了 Sentry 等产品)无法捕获到该错误,因为错误已被 try...catch 内部消化。
try {
// 预期 a = {}
// 结果
a = undefined
a.a = 1
} catch (e) {
console.error(e)
// 公司内部的上报函数
someReportFunction('sendEvent', {
name: 'try_catch_error',
params: {
errorMsg: e.message,
errorStack: e.stack
},
});
}
2. 错用 throw
网络上存在误导性的教程,建议使用 throw 语句。必须明确:throw 会阻断代码执行,这一点需要反复强调,throw 会阻断代码,throw 会阻断代码,throw 会阻断代码。

例如:
console.log(111)
try {
// 预期 a = {}
// 结果
a = undefined
a.a = 1
} catch (e) {
console.error(e)
throw e // throw会阻断代码,导致下面不执行
}
console.log(222) // 不能执行到这一行
当然,throw 并非毫无用处,但它必须严格限制在 try 块内部使用,严禁在 try 块之外(包括 catch 块)直接使用 throw。
console.log(111)
try {
throw new Error(111)
} catch (e) {
console.error(e)
}
console.log(222)
function getData () {
if (...) {
...
} else {
throw new Error(111)
}
}
console.log(111)
try {
getData()
} catch (e) {
console.error(e)
}
console.log(222)
3. 异步代码 catch 不到,还是会被阻断
console.log(111111111)
try {
setTimeout(() => {
a = undefined
a.a = 1 // 代码被阻断于此
console.log('error') // 不能执行到这一行
}, 0)
} catch (e) {
console.error(e) // 异步代码catch不到
}
console.log(222222222)
setTimeout(() => {
console.log('setTimeout') // 浏览器可以执行到这一行,node的不行(node14和16版本都test了)
}, 2000)
4. import() 和 require() 的错误捕获表现不一致
// a.js
console.log(111111111)
try {
require('./b.js')
} catch (e) {
console.log('error') // 错误会被正常catch到
console.error(e)
}
console.log(222222222)
setTimeout(() => {
console.log('setTimeout')
}, 2000)
// b.js
console.log(1)
a = undefined
a.a = 1
console.log(2)
// 结果打印 (require被正常捕获)
111111111
1
error
TypeError: Cannot set property 'a' of undefined
...
...
222222222
setTimeout
- 将上述代码替换为使用 import() 动态导入。
// a.js
console.log(111111111)
try {
import('./b.js')
} catch (e) {
console.log('error') // 错误没有被catch到
console.error(e)
}
console.log(222222222)
setTimeout(() => {
console.log('setTimeout')
}, 2000)
// b.js
console.log(1)
a = undefined
a.a = 1
console.log(2)
// 结果打印 (import的 错误没有被catch到)
111111111
222222222
1
(node:92673) UnhandledPromiseRejectionWarning: TypeError: Cannot set property 'a' of undefined
...
setTimeout
正确捕获 import() 的方式:由于 import() 返回一个 Promise,因此应使用 Promise 的 catch 方法或 .catch() 链式调用进行处理。
import('./b.js')
.catch(e => {
console.log('error')
console.error(e)
})
结论:
- try...catch 无法捕获 import() 模块加载过程中的错误,但 require 同步加载的错误可以被正常捕获。
- 对于 import(),应使用 Promise 的方法进行 catch 处理。
背景:
- require 属于运行时加载,其机制类似于函数调用。
- import() 属于动态导入,执行延迟加载,属于异步任务(微任务),且返回 Promise 对象。
以上即为关于 JavaScript 代码稳定性建设中防止代码阻断的详细内容,更多关于 JavaScript 稳定建设的资料请关注本站其它相关文章!
JS语法错误会阻止加载吗?区分SyntaxError与资源加载失败
2026-11-05 16:08:46
JavaScript常见SyntaxError语法错误排查与修复方法
2026-11-05 13:58:44
JS中slice、substring和substr截取字符串的区别
2026-11-05 13:43:47
JS 转 TS 手动迁移最佳实践:从配置 tsconfig 到消除 any 类型
2026-11-05 11:53:32
为什么JS数组push后得到的是数字而不是数组?
2026-11-05 09:59:18
