前端错误处理最佳实践:别让你的应用崩溃了!

前端错误处理最佳实践:别让你的应用崩溃了!

毒舌时刻

错误处理?听起来就像是前端工程师为了显得自己很专业而特意搞的一套复杂流程。你以为随便加个try-catch就能解决所有错误?别做梦了!到时候你会发现,错误处理的代码比业务代码还多,维护起来比业务代码还麻烦。

你以为console.error就能记录所有错误?别天真了!console.error只会在控制台打印错误,用户根本看不到,也无法帮助你分析错误原因。还有那些所谓的错误监控工具,看起来高大上,用起来却各种问题。

为什么你需要这个

  1. 提高用户体验:良好的错误处理可以避免应用崩溃,提高用户体验。
  2. 减少生产环境问题:及时捕获和处理错误可以减少生产环境中的问题。
  3. 便于调试:良好的错误处理可以帮助你更快地定位和解决问题。
  4. 提高代码可靠性:错误处理可以提高代码的可靠性,减少意外情况的发生。
  5. 监控和分析:错误处理可以帮助你监控和分析应用的运行状态,发现潜在问题。

反面教材

// 1. 忽略错误 function fetchData() { fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)); } // 2. 过度使用try-catch function processData(data) { try { if (data) { try { const processedData = data.map(item => { try { return item.value * 2; } catch (error) { console.error('Error processing item:', error); return 0; } }); return processedData; } catch (error) { console.error('Error mapping data:', error); return []; } } else { return []; } } catch (error) { console.error('Error processing data:', error); return []; } } // 3. 错误信息不明确 function calculateTotal(price, quantity) { if (typeof price !== 'number') { throw new Error('Invalid input'); } return price * quantity; } // 4. 缺少全局错误处理 window.addEventListener('error', (event) => { console.error('Global error:', event.error); }); // 5. 不记录错误 function login(username, password) { if (!username || !password) { throw new Error('Username and password are required'); } // 登录逻辑 } 

问题

  • 忽略错误,导致应用崩溃
  • 过度使用try-catch,导致代码变得臃肿
  • 错误信息不明确,难以定位问题
  • 缺少全局错误处理,无法捕获所有错误
  • 不记录错误,无法分析错误原因

正确的做法

错误处理策略

// 1. 基本错误处理 async function fetchData() { try { const response = await fetch('/api/data'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('Error fetching data:', error); throw error; } } // 2. 自定义错误类 class ApiError extends Error { constructor(message, status) { super(message); this.name = 'ApiError'; this.status = status; } } async function fetchUserData(id) { try { const response = await fetch(`/api/users/${id}`); if (!response.ok) { throw new ApiError(`Failed to fetch user: ${response.status}`, response.status); } const data = await response.json(); return data; } catch (error) { if (error instanceof ApiError) { console.error('API error:', error.message); } else { console.error('Unexpected error:', error); } throw error; } } // 3. 错误边界(React) class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, errorInfo) { console.error('Error caught by boundary:', error, errorInfo); } render() { if (this.state.hasError) { return <div>Something went wrong. Please try again later.</div>; } return this.props.children; } } // 4. 全局错误处理 window.addEventListener('error', (event) => { console.error('Global error:', event.error); // 发送错误到监控服务 sendErrorToMonitoring(event.error); }); window.addEventListener('unhandledrejection', (event) => { console.error('Unhandled promise rejection:', event.reason); // 发送错误到监控服务 sendErrorToMonitoring(event.reason); }); 

错误监控

// 1. 使用Sentry // 安装 // npm install @sentry/react // 初始化 import * as Sentry from '@sentry/react'; import { BrowserTracing } from '@sentry/tracing'; Sentry.init({ dsn: 'YOUR_DSN', integrations: [new BrowserTracing()], tracesSampleRate: 1.0, }); // 捕获错误 try { // 可能会出错的代码 } catch (error) { Sentry.captureException(error); } // 2. 自定义错误监控 function sendErrorToMonitoring(error) { // 收集错误信息 const errorData = { message: error.message, stack: error.stack, url: window.location.href, userAgent: navigator.userAgent, timestamp: new Date().toISOString() }; // 发送到监控服务 fetch('/api/error-monitoring', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(errorData) }); } // 3. 错误日志 function logError(error, context = {}) { console.error('Error:', error); console.error('Context:', context); // 发送到服务器 sendErrorToMonitoring({ ...error, context }); } 

用户友好的错误提示

// 1. 错误提示组件 function ErrorMessage({ error, onRetry }) { return ( <div className="error-message"> <h3>Oops! Something went wrong.</h3> <p>{error.message}</p> {onRetry && <button onClick={onRetry}>Try Again</button>} </div> ); } // 2. 表单错误处理 function LoginForm() { const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const handleSubmit = async (e) => { e.preventDefault(); setError(null); setLoading(true); try { // 登录逻辑 } catch (error) { setError(error); } finally { setLoading(false); } }; return ( <form onSubmit={handleSubmit}> {error && <ErrorMessage error={error} />} {/* 表单字段 */} <button type="submit" disabled={loading}> {loading ? 'Loading...' : 'Login'} </button> </form> ); } // 3. 异步操作错误处理 function DataFetcher() { const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { async function fetchData() { try { const response = await fetch('/api/data'); if (!response.ok) { throw new Error('Failed to fetch data'); } const data = await response.json(); setData(data); } catch (error) { setError(error); } finally { setLoading(false); } } fetchData(); }, []); if (loading) return <div>Loading...</div>; if (error) return <ErrorMessage error={error} onRetry={() => window.location.reload()} />; return <div>{/* 渲染数据 */}</div>; } 

最佳实践

// 1. 分层错误处理 // 底层:捕获并转换错误 async function apiCall(url, options) { try { const response = await fetch(url, options); if (!response.ok) { throw new ApiError(`API error: ${response.status}`, response.status); } return await response.json(); } catch (error) { if (error instanceof ApiError) { throw error; } else { throw new ApiError('Network error', 0); } } } // 中层:处理业务逻辑错误 async function getUserData(id) { try { return await apiCall(`/api/users/${id}`); } catch (error) { if (error.status === 404) { throw new Error('User not found'); } else { throw error; } } } // 上层:处理UI错误 function UserProfile({ userId }) { const [user, setUser] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { async function loadUser() { try { const userData = await getUserData(userId); setUser(userData); } catch (error) { setError(error); } finally { setLoading(false); } } loadUser(); }, [userId]); if (loading) return <div>Loading...</div>; if (error) return <ErrorMessage error={error} />; return <div>{/* 渲染用户信息 */}</div>; } // 2. 错误恢复策略 function AutoRetryComponent({ fetchData, maxRetries = 3 }) { const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [retryCount, setRetryCount] = useState(0); useEffect(() => { async function loadData() { try { const result = await fetchData(); setData(result); } catch (error) { if (retryCount < maxRetries) { setRetryCount(prev => prev + 1); // 延迟重试 setTimeout(loadData, 1000 * (retryCount + 1)); } else { setError(error); } } finally { setLoading(false); } } loadData(); }, [fetchData, maxRetries, retryCount]); if (loading) return <div>Loading...</div>; if (error) return <ErrorMessage error={error} />; return <div>{/* 渲染数据 */}</div>; } 

毒舌点评

错误处理确实很重要,但我见过太多开发者滥用这个特性,导致代码变得过于复杂。

想象一下,当你为了处理所有可能的错误,写了大量的try-catch块,结果导致代码量增加了几倍,这真的值得吗?

还有那些过度使用错误监控的开发者,为了捕获所有错误,在每个函数中都添加错误处理,结果导致代码变得难以理解和维护。

所以,在进行错误处理时,一定要把握好度。不要为了处理所有可能的错误而牺牲代码的简洁性,要根据实际情况来决定错误处理的策略。

当然,对于大型应用来说,良好的错误处理是必要的。但对于小型应用,过度的错误处理反而会增加开发成本和维护难度。

最后,记住一句话:错误处理的目的是为了提高应用的可靠性和用户体验,而不是为了炫技。如果你的错误处理策略导致应用变得更难维护或用户体验变得更差,那你就失败了。

Read more

Llama-2-7b在昇腾NPU上的六大核心场景性能基准报告

Llama-2-7b在昇腾NPU上的六大核心场景性能基准报告

引言 随着大语言模型(LLM)技术的飞速发展,其底层算力支撑硬件的重要性日益凸显。传统的GPU方案之外,以华为昇腾(Ascend)为代表的NPU(神经网络处理单元)正成为业界关注的焦点。为了全面、深入地评估昇腾NPU在实际LLM应用中的性能表现,我们进行了一项针对性的深度测评。本次测评选用业界广泛应用的开源模型Llama-2-7b,在 Atlas 800T A2 训练卡 平台上进行部署、测试与分析,旨在为开发者和决策者提供一份详实的核心性能数据、深度的场景性能剖析、以及可靠的硬件选型与部署策略参考。 模型资源链接:本项目测评使用的模型权重及相关资源可在 GitCode 社区获取:https://gitcode.com/NousResearch/Llama-2-7b-hf 一、 测评环境搭建与准备 扎实的前期准备是确保测评数据准确可靠的基石。本章节将详细记录从激活昇腾NPU计算环境到完成所有依赖库安装的全过程,确保测试流程的透明与可复现性。 1.1 激活NPU Notebook实例 我们通过GitCode平台进行本次操作。首先,需要进入项目环境并激活一个Notebook实例,这

一文读懂UGC、PGC、PUGC、OGC、MGC、BGC与AIGC

一文读懂UGC、PGC、PUGC、OGC、MGC、BGC与AIGC 在当今这个信息爆炸的数字时代,我们无时无刻不被各种形式的内容所包围——从短视频、直播到图文资讯、专业评测。你或许经常听到UGC、PGC、AIGC这些听起来很“高级”的缩写,但它们究竟代表什么?彼此之间又有什么区别和联系?今天,就让我们一次性说清楚内容创作领域的各种“GC”(Generated Content)。 文章目录 * 一文读懂UGC、PGC、PUGC、OGC、MGC、BGC与AIGC * 1 核心区别:是“谁”在创作内容? * 2 UGC (User Generated Content) - 用户生成内容 * 3 PGC (Professionally Generated Content) - 专业生成内容 * 4

GitHub Copilot AI 编程超全使用教程,从入门到精通

GitHub Copilot AI 编程超全使用教程,从入门到精通

前言 作为 GitHub 推出的 AI 编程助手,GitHub Copilot 凭借强大的代码补全、自然语言交互、自动化开发等能力,成为了开发者提升编码效率的 “神器”。它能支持主流 IDE(VS Code、IntelliJ IDEA、Eclipse 等)、终端等多环境,还可自定义配置、切换 AI 模型,适配个人和团队的不同开发需求。本文结合 GitHub 官方文档和实际使用经验,用通俗易懂的方式讲解 Copilot 的完整使用方法,从环境搭建到高级技巧,再到故障排除,一站式搞定 Copilot AI 编程! 一、GitHub Copilot 核心能力一览 在开始使用前,先快速了解 Copilot 的核心功能,清楚它能帮我们解决哪些开发问题: 1. 智能代码补全:

Copilot vs Claude Code终极对决哪个会更好用呢?

Copilot vs Claude Code终极对决哪个会更好用呢?

📊 核心差异:一句话概括 * GitHub Copilot:你的智能代码补全器 * Claude Code:你的全栈AI开发伙伴 🎯 一、产品定位对比 GitHub Copilot:专注代码补全 <TEXT> 定位:AI结对编程助手 核心理念:让你写代码更快 核心功能:基于上下文的代码建议和补全 收费模式:个人$10/月,企业$19/用户/月 Claude Code:全栈开发加速器 <TEXT> 定位:AI驱动的开发平台 核心理念:提升整个开发流程效率 核心功能:代码生成+架构设计+调试+部署 收费模式:按token计费,灵活弹性 ⚡ 二、核心技术对比