前端异常处理规范

384 阅读5分钟

引言

简介

异常处理在前端开发中的重要性不言而喻。构建稳定、可靠的前端应用,防止用户面临不友好的错误信息或者导致应用崩溃,使开发人员更容易追踪和调试问题。

目的

前端异常处理应当在代码中使用 try-catch 块或其他适当的方式捕获异常,记录异常的详细信息,以便及时发现问题并更好地诊断和修复问题;在关键业务逻辑中引入容错机制,确保系统在面临异常情况时依然能够提供基本的功能;建立异常监控系统,及时发现并通知开发团队异常情况,以便快速响应和修复;

前端异常处理

1、异常主动上报场景

为保证代码统一性,vue文件里处理的逻辑捕获均使用 try-Catch 形式,异步代码用 async-await 形式:

a、异步代码中的错误处理:
try {
 // 异步操作,如AJAX请求或定时器
 const response = await axios(url, options);
} catch (error) {
 // console.error("发生错误:", error);
 errorHandler(error);
}
b、JSON 解析:
try {
 var jsonData = JSON.parse(invalidJsonString);
} catch (error) {
 // console.error("JSON解析错误:", error);
 errorHandler(error);
}
c、DOM 操作:
try {
 // 可能会引发DOM异常的操作
} catch (error) {
 // console.error("DOM操作错误:", error);
 errorHandler(error);
}
d、资源加载:
try {
 // 尝试加载资源,如图片、脚本等
} catch (error) {
 // console.error("资源加载错误:", error);
 errorHandler(error);
}
e、本地存储:
try {
 // 尝试访问本地存储
} catch (error) {
 // console.error("本地存储访问错误:", error);
 errorHandler(error);
}
f、参数为函数,被调用时:
function test(fn){
 try {
  fn()
 } catch (error) {
  errorHandler(error);
 }
} 

在这些情况下,try-catch 语句可以帮助捕获异常并提供更友好的错误处理,避免整个应用程序崩溃。

2、统一的错误处理规范

  • 编写一个统一的错误处理函数,接收错误对象,并执行适当的操作,如打印错误对象、向服务器上报错误、显示用户友好的错误消息等,可以帮助简化代码并确保一致性。
function errorHandler(error, msg) {
   // 打印错误对象
   console.error('Error:', error);
   // 向服务器主动报告错误
   reportErrorToServer(error);
   // 还可以执行其他适当的操作,如在非生产环境显示通知
   if(!prd) showErrorMessageToUser(msg || '系统异常,请稍后再试');
}

// 例子:在代码中调用错误处理函数
try {
   throw new Error('This is a test error.');
} catch (error) {
   errorHandler(error);
}

3、异常日志规范

在JavaScript应用程序中,实现异常日志规范有助于快速诊断和解决问题。通常包括以下关键信息:

a、错误消息: 记录详细的错误消息,包括错误描述、发生的位置以及可能的原因。这可以通过捕获错误对象的message属性和堆栈信息来实现。

b、堆栈跟踪: 记录堆栈跟踪信息,以便追踪异常发生的位置。这有助于开发人员迅速定位和修复问题。

c、用户上下文: 如果可能,记录与用户相关的上下文信息,例如用户ID、操作、浏览器信息等。这有助于理解用户遇到的问题背后的背景。

d、时间戳: 记录异常发生的时间戳,以便能够按时间顺序检查日志,追溯问题发生的时间。

e、环境信息: 记录应用程序运行的环境信息,包括浏览器版本、操作系统、设备信息等。这对于排查特定环境下的问题很有帮助。

f、保护用户隐私: 在记录日志时,确保不包含敏感信息,以保护用户隐私。

g、存储与管理:描述日志的存储方式和周期,以及如何安全高效地管理这些日志。

4、异常编码规范

在代码中使用try-catch块或其他适当的方式捕获异常,以便及时发现问题。

  • 同步代码的错误处理
try {
    const errorCake = dessert.getDessert(CAKE);
} catch(error) {
    errorHandler(error);
}
  • 异步代码setTimeout和addEventListener的错误处理
button.addEventListener("click", function() {
    try {
        throw Error("error");
    } catch(error) {
        errorHandler(error);
    }
});
  • 异步代码Promise的错误处理
function fetchData(url, options) {
 return new Promise((resolve, reject) => {
   // 异步请求
   fetch(url, options)
     .then(response => {
       if (!response.ok) {
         throw new Error(`HTTP error! Status: ${response.status}`);
       }
       return response.json();
     })
     .then(data => {
       resolve(data);
     })
     .catch(error => {
       errorHandler(error, '页面接口出错,请稍后再试');
       reject(error);
     });
 });
}
  • async/await的错误抛出
async function fetchData(url, options) {
 try {
   const response = await axios(url, options);
   if (response.status !== 200) {
     throw new Error(`HTTP error! Status: ${response.status}`);
   }
   return response.data;
 } catch (error) {
   errorHandler(error, '页面接口出错,请稍后再试');
 }
}

5、异常错误捕获方式

在 JavaScript 开发中,正确处理执行异常错误是提高应用稳定性和用户体验的关键一环。JavaScript 提供了多种方式来捕获和处理执行时异常,包括同步和异步错误。

  • try...catch 语句

只能捕获同步代码中的错误。在异步代码中,如 setTimeout 或 Promise 内部抛出的错误,try...catch 无法直接捕获。

try {
 // 尝试执行的代码,可能会抛出异常 throw new Error('Oops!');
} catch (error) {
 // 错误处理逻辑 console.log(error.message); 
}
  • window.onerror

可以捕获未被 try...catch 捕获的所有同步和一部分异步错误。可以捕获资源(如图片、脚本、样式表等)加载失败的错误。只能捕获发生在同源脚本中的错误。不适合处理异步错误,如通过 fetch 发起的网络请求错误等。

window.onerror = function(message, source, lineno, colno, error) {
    console.log('捕获到全局错误:', message);
    return true;  // 阻止默认处理(如浏览器控制台的错误报告)
};
  • window.addEventListener('error')

不会覆盖其他的 error 事件监听器,可以添加多个监听器。通过为特定的 HTML 元素(如 <img><script><link> 等)添加 error 事件监听器,可以更精细地处理单个资源的加载失败。

如果你需要全局捕获并处理所有类型的错误(包括语法错误、运行错误以及资源加载错误),window.onerror 是一个不错的选择。如果你需要对特定资源的加载错误进行详细监控和特定处理,应该使用 addEventListener 方法来监听这些资源的 error 事件。

window.addEventListener('error', function(event) {
    console.log('捕获到错误:', event.message);
    event.preventDefault();  // 阻止默认处理
});
  • Promise.catchasync/await 中的 try...catch

异步友好:可以在异步代码块中直接处理错误。

fetch('some-url')
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json();
    })
    .catch(error => {
        console.log('有一个问题:', error.message);
    });
  • addEventListener('unhandledrejection')

用来捕获Promise中未被处理的拒绝(即未被.catch()捕获或reject没有对应的catch处理器的情况)。

window.addEventListener('unhandledrejection', function(event) {
    console.error('Promise 拒绝未被处理:', event.promise);
    console.error('拒绝的原因:', event.reason);
    // event.promise 是被拒绝的 Promise 对象
    // event.reason 是 Promise 被拒绝的原因
});