前端 JavaScript 脚本加载错误处理
在前端开发中,JavaScript 错误处理是应用稳定性和良好用户体验的关键。无论是加载外部脚本、执行异步操作,还是处理运行时错误,我们都需要确保错误能够被及时捕获和妥善处理。否则,未处理的错误可能导致页面崩溃或不完整的功能,影响用户体验。
本文将介绍几种常见的 JavaScript 错误处理方法,包括如何监听外部脚本的加载错误、捕获执行过程中的同步和异步错误,以及如何应对 Promise 和 async/await 中的错误。
一、使用 onerror 监听脚本加载错误
适用范围
onerror 主要用于单个 <script> 标签,用于捕获该脚本加载失败的错误。常用于处理外部 JavaScript 文件加载失败的场景。需要注意的是,onerror 仅能捕获 脚本加载失败的错误,例如文件不存在、路径错误等,不能捕获 脚本执行中的错误。
跨域限制
当加载外部脚本时,如果涉及跨域请求,必须确保外部服务器设置了正确的 CORS(跨域资源共享) 头,以允许浏览器加载该脚本并触发相关的错误事件。
示例:监听外部脚本加载错误
假设我们要加载一个外部 JavaScript 文件,并希望在脚本加载失败时进行处理。我们可以在 <script> 标签中直接使用 onerror 属性来监听错误。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Script Error Handling</title> </head> <body> <script> // 错误处理函数 function handleScriptError(event) { console.error("Script failed to load:", event.target.src); alert("Sorry, the script could not be loaded."); } </script> <!-- 引入外部脚本 --> <script src="https://example.com/nonexistent.js" onerror="handleScriptError(event)"></script> </body> </html>
在上面的示例中,我们尝试加载一个不存在的脚本 https://example.com/nonexistent.js。当该脚本无法加载时,onerror 事件会被触发,调用 handleScriptError 函数,输出错误信息,并通过 alert 提示用户。
二、使用 window.onerror 捕获全局错误
适用范围
window.onerror 是一个全局错误处理程序,用于捕获页面中的所有 JavaScript 错误(包含外部js的错误和异步的setTimeout、setInterval错误)。例如,语法错误、运行时错误等。通过它可以方便地集中管理页面的错误处理。
不能捕获的错误
window.onerror 无法捕获外部资源加载错误(如 <script> 标签的加载错误)以及 Promise 错误和 try...catch 已捕获的错误
window.onerror 捕获全局错误。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>window.onerror Example</title> </head> <body> <h1>Welcome to my website!</h1> <script> // 设置 window.onerror 来捕获全局的 JavaScript 错误 window.onerror = function (message, source, lineno, colno, error) { console.error("Error message:", message); // 错误信息 console.error("Error source:", source); // 错误发生的文件 console.error("Error line:", lineno); // 错误发生的行号 console.error("Error column:", colno); // 错误发生的列号 console.error("Error object:", error); // 错误对象(包含详细信息) // 返回 true 来表示错误已被处理(防止浏览器默认处理) return true; }; // 这里故意使用一个未定义的函数调用 causeError(); </script> </body> </html>
在上述示例中,window.onerror 捕获了调用 causeError() 时抛出的 ReferenceError。window.onerror 提供了错误信息、错误源文件、行号、列号等详细信息,便于调试。
示例:使用 window.onerror 捕获异步操作(如 setTimeout、setInterval)中发生的 异常。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>window.onerror Example</title> </head> <body> <h1>Welcome to my website!</h1> <script> // 设置 window.onerror 来捕获全局的 JavaScript 错误 window.onerror = function (message, source, lineno, colno, error) { console.error("Error message:", message); // 错误信息 console.error("Error source:", source); // 错误发生的文件 console.error("Error line:", lineno); // 错误发生的行号 console.error("Error column:", colno); // 错误发生的列号 console.error("Error object:", error); // 错误对象(包含详细信息) // 返回 true 来表示错误已被处理(防止浏览器默认处理) return true; }; // 这里故意使用一个未定义的函数调用 //异步报错 setTimeout(() => { nonExistentFunction() }, 300) </script> </body> </html>
示例:使用 window.onerror 捕获外部的js错误。
window.onerror 必须在任何 JavaScript 错误发生之前定义,否则它无法捕获已经发生的错误。如果您将 window.onerror 放在 <script src="..."></script> 之后加载外部 JS 文件,外部文件中的错误将不会触发 window.onerror。
<script>
// 设置 window.onerror 来捕获全局的 JavaScript 错误
window.onerror = function (message, source, lineno, colno, error) {
console.error("Error message:", message); // 错误信息
console.error("Error source:", source); // 错误发生的文件
console.error("Error line:", lineno); // 错误发生的行号
console.error("Error column:", colno); // 错误发生的列号
console.error("Error object:", error); // 错误对象(包含详细信息)
// 返回 true 来表示错误已被处理(防止浏览器默认处理)
return true;
};
</script>
<script src=" http://localhost:5173/src/assets/index.js"></script>
外部的js文件,在外边js内部触发错误,也可以触发window.oerror事件
function fn() { throw new Error("This is a test error"); } fn() export default fn;
跨域脚本的限制
如果外部脚本是跨域引入的(如 CDN 上的脚本),浏览器出于安全考虑会限制错误信息的捕获,此时 window.onerror 只能获取到模糊的错误信息:
捕获到错误: Script error. 错误文件: "" 错误位置: 0:0
解决方法:
为跨域脚本添加 CORS 响应头 和 crossorigin 属性:
-
服务端配置:
-
确保跨域脚本的响应头包含:
-
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: *
客户端配置:
-
在引入脚本时添加
crossorigin属性:
<script src="https://cdn.example.com/external.js" crossorigin></script>
这样,window.onerror 就能捕获到完整的错误信息。
window.onerror 参数说明
- message:错误信息(例如
Uncaught ReferenceError)。 - source:错误发生的 JavaScript 文件的 URL。
- lineno:错误发生的行号。
- colno:错误发生的列号。
- error:包含详细错误信息的
Error对象。
通过返回 true,可以阻止浏览器的默认错误处理,避免重复输出错误信息。如果不想阻止默认行为,可以将 return true 删除。
三、使用 try...catch 捕获执行过程中的错误
适用范围
try...catch 用于捕获 JavaScript 执行过程中的错误,尤其适用于同步代码块中的错误。它对于动态加载脚本时非常有效,但 不能捕获 <script> 标签加载错误。
示例:使用 try...catch 捕获执行中的错误
<script>
try {
// 这会抛出错误,因为 nonExistentFunction 并未定义
nonExistentFunction();
} catch (error) {
console.error("Caught error:", error);
}
</script>
在上面的示例中,try...catch 捕获了 nonExistentFunction() 抛出的 ReferenceError,并输出错误信息。
四、Promise、async/await 中的异步错误处理
使用 .catch() 处理 Promise 错误
当使用 Promise 时,异步操作的错误可以通过 .catch() 来捕获。.catch() 用于捕获 Promise 被拒绝(rejected)时抛出的错误。
示例:使用 Promise 和 .catch() 处理错误
const myPromise = new Promise((resolve, reject) => { // 模拟异步操作 const success = false; if (success) { resolve('Operation succeeded'); } else { reject('Operation failed'); } }); // 通过 catch 捕获错误 myPromise .then(result => console.log(result)) .catch(error => console.error('Error caught:', error)); // 捕获错误
如果你不使用 .catch(),而是直接使用 .then(),未处理的错误将导致 未处理的 Promise 拒绝错误,这在某些环境中可能会导致应用崩溃。
使用 async/await 捕获异步错误
async/await 是基于 Promise 的语法糖,它使得异步代码看起来更像同步代码。通常我们会在 async 函数中使用 try...catch 来捕获异步操作中的错误。
示例:async/await 的错误处理
async function fetchData() { try { const response = await fetch('https://example.com/api'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error occurred:', error); // 捕获错误 } } fetchData();
五、补充:全局监听未处理的 Promise 错误
除了在每个 Promise 或 async/await 中处理错误,你还可以通过监听全局的 unhandledrejection 来捕获未处理的 Promise 错误。这有助于确保所有异步错误都有处理。
示例:捕获未处理的 Promise 错误
window.addEventListener('unhandledrejection', function(event) { console.error('Unhandled promise rejection:', event.reason); });
六、捕获外部 JavaScript 脚本执行时的错误
window.onerror 在 Vue 项目和Reacr项目这种框架项目中也可以用来捕获外部 JavaScript 脚本执行时的错误,包括第三方库或外部脚本的运行时错误。
适用范围:
-
外部脚本加载错误:
- 如果一个外部脚本因为路径错误、网络问题等原因加载失败(例如返回 404 错误),
window.onerror可以捕获这些错误。 - 但是需要注意,
window.onerror只能捕获加载错误,不会捕获其他类型的错误(例如,脚本加载成功后发生的运行时错误)。
- 如果一个外部脚本因为路径错误、网络问题等原因加载失败(例如返回 404 错误),
-
外部脚本执行错误:
- 如果外部脚本加载成功,但在执行过程中发生了 JavaScript 错误,
window.onerror也能捕获这些错误。 - 比如,第三方脚本抛出了一个运行时错误(如
ReferenceError),window.onerror会捕获这个错误,并提供错误信息。
- 如果外部脚本加载成功,但在执行过程中发生了 JavaScript 错误,
重要注意事项:
window.onerror捕获的是 全局错误,包括在外部脚本执行过程中抛出的错误。window.onerror不能 捕获在外部脚本加载时的CORS(跨域资源共享)相关错误。如果外部服务器没有正确设置CORS头部,浏览器可能会阻止脚本的加载并抛出错误,此时需要通过script.onerror来捕获加载错误。- 对于
Promise相关的错误,window.onerror无法直接捕获。如果外部脚本中有Promise被拒绝的情况,应该使用Promise的.catch()或者全局监听unhandledrejection事件来捕获。
不能捕获的错误
虽然 window.onerror 仍然可以捕获一些全局错误,但在现代框架中渲染阶段组件的错误无法捕获到。
- 对于框架内部的错误,
window.onerror通常捕获不到 - 框架有自己的错误处理机制
- Vue: errorHandler
- React: ErrorBoundary
Vue的错误处理:
Vue.config.errorHandler = (err, vm, info) => {
// 渲染错误处理
// err: 错误对象
// vm: 组件实例
// info: 错误信息
}
React的错误处理:
class ErrorBoundary extends React.Component {
componentDidCatch(error, errorInfo) {
// 渲染期间的错误捕获
// error: 错误对象
// errorInfo: 错误详细信息
}
}
这些机制确实主要处理组件渲染过程中的错误,而不是全局的 JavaScript 执行错误。对于其他类型的错误,仍然需要使用 window.onerror 或其他全局错误捕获机制。
七、总结
-
onerror
- 用途:用于捕获
<script>标签的资源加载错误。 - 限制:无法捕获脚本执行中的错误。
- 跨域限制:加载跨域脚本时需要服务器设置 CORS 头,允许浏览器加载并触发相关的错误事件。
- 即使配置 CORS 并触发
onerror,仍无法获取具体错误原因(如 HTTP 状态码、网络错误类型),只能获取到 "加载失败" 的事件通知和脚本 URL
- 用途:用于捕获
-
window.onerror
- 用途:用于捕获全局(包含外部引入的js) JavaScript 错误以及异步操作(如
setTimeout、setInterval)中发生的 异常。(如语法错误和运行时错误)。前提是它们没有被try...catch捕获。 - 限制:无法捕获外部资源加载错误(如
<script>标签的加载错误)以及 Promise 错误。 - 跨域:为跨域脚本添加 CORS 响应头 和
crossorigin属性
- 用途:用于捕获全局(包含外部引入的js) JavaScript 错误以及异步操作(如
-
try...catch
- 用途:适用于同步代码的错误处理,能够捕获执行过程中的错误。
- 应用:适用于函数调用、代码执行中的错误,或在
setTimeout、setInterval等异步操作的回调中捕获错误。 - 限制:无法捕获
<script>标签的加载错误。
-
Promise 的 .catch()
- 用途:用于捕获 Promise 的拒绝错误,确保异步操作中的错误得到处理。
- 应用:捕获异步操作的失败(例如,网络请求失败)。
-
async/await 与 try...catch
- 用途:用于捕获异步操作中的错误,尤其是在
async函数中处理await操作时。 - 应用:处理
async函数中的异常和错误。
- 用途:用于捕获异步操作中的错误,尤其是在
-
unhandledrejection
- 用途:用于捕获未处理的 Promise 错误,确保所有异步错误都有处理。
- 应用:监听未被
.catch()捕获的 Promise 拒绝错误。

浙公网安备 33010602011771号