try-catch错误捕获机制
try-catch-finally结构
try {
// 尝试执行的代码,可能会抛出错误
const result = await riskyOperation();
} catch (error) {
// 捕获错误,进行错误处理
console.error('操作失败:', error);
} finally {
// 无论成功或失败都会执行的代码
cleanup();
}错误类型分类
try {
await fetch('https://api.example.com/data');
} catch (error) {
if (error instanceof TypeError) {
// 网络错误或URL错误
console.error('网络错误:', error.message);
} else if (error instanceof SyntaxError) {
// JSON解析错误
console.error('数据格式错误');
} else if (error.name === 'AbortError') {
// 请求被取消
console.error('请求超时');
} else {
// 其他未知错误
console.error('未知错误:', error);
}
}异步操作:使用async/await处理异步API调用
async/await基本概念
// 传统Promise方式(回调地狱)
function oldWay() {
fetch(url)
.then(response => response.json())
.then(data => {
return processData(data);
})
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});
}
// async/await方式(同步写法)
async function newWay() {
try {
const response = await fetch(url);
const data = await response.json();
const processed = await processData(data);
console.log(processed);
} catch (error) {
console.error(error);
}
}await的工作机制
async function example() {
console.log('1. 开始执行');
// await会暂停函数执行,等待Promise完成
const result = await someAsyncFunction();
// ⬆️ 这里会"等待",但不会阻塞主线程
console.log('3. 异步操作完成:', result);
}
console.log('0. 函数调用前');
example();
console.log('2. 函数已调用(不会等待)');
// 输出顺序: 0 → 1 → 2 → 3并行与串行执行
// 1. 串行执行(一个接一个)
async function serialExecution() {
console.time('串行');
const result1 = await fetchData1(); // 等待2秒
const result2 = await fetchData2(); // 等待3秒(等第一个完成后才开始)
console.timeEnd('串行'); // 总耗时≈5秒
}
// 2. 并行执行(同时进行)
async function parallelExecution() {
console.time('并行');
const promise1 = fetchData1(); // 立即开始,不等待
const promise2 = fetchData2(); // 立即开始,不等待
// 使用Promise.all同时等待多个Promise
const [result1, result2] = await Promise.all([promise1, promise2]);
console.timeEnd('并行'); // 总耗时≈3秒(取最长的)
}
// 3. 竞赛模式(谁先完成用谁)
async function raceExecution() {
const result = await Promise.race([
fetchWithTimeout('api1', 2000),
fetchWithTimeout('api2', 2000)
]);
// 第一个完成的(无论成功或失败)会被返回
}错误处理模式对比
// 模式1:每个await单独try-catch
async function individualCatch() {
let data;
try {
data = await fetchData();
} catch (error) {
console.error('获取数据失败:', error);
return;
}
try {
await processData(data);
} catch (error) {
console.error('处理数据失败:', error);
}
}
// 模式2:统一错误处理
async function unifiedCatch() {
try {
const data = await fetchData();
await processData(data);
await saveData(data);
} catch (error) {
// 任何一个步骤失败都会跳到这里
handleError(error);
}
}
// 模式3:使用高阶函数包装
function withErrorHandling(asyncFunc) {
return async function(...args) {
try {
return await asyncFunc(...args);
} catch (error) {
console.error('函数执行失败:', error);
return { error: true, message: error.message };
}
};
}
const safeFetch = withErrorHandling(fetchData);
const result = await safeFetch(url);实际案例
<script>
// 当DOM内容完全加载后执行(确保所有HTML元素已存在)
document.addEventListener('DOMContentLoaded', function() {
// 获取页面中的按钮元素
const reloadBtn = document.getElementById('reload-btn');
// 获取显示结果的div元素
const resultDiv = document.getElementById('result');
// 获取显示服务器URL的span元素(虽然代码中未使用,但已定义)
const serverUrlSpan = document.getElementById('server-url');
// 获取当前页面的主机名和端口号,用于构建API URL(备用)
const currentHost = window.location.hostname;
const currentPort = window.location.port;
// 为"更新数据"按钮添加点击事件监听器
reloadBtn.addEventListener('click', async function() {
// 禁用按钮,防止用户重复点击
reloadBtn.disabled = true;
// 更改按钮文字提示用户正在更新
reloadBtn.textContent = '更新中...';
// 清空之前显示的结果
resultDiv.className = 'hidden'; // 添加隐藏类
resultDiv.innerHTML = ''; // 清空内容
try {
// 显示加载状态
resultDiv.className = 'loading'; // 添加加载样式类
resultDiv.textContent = '正在重新加载数据...';
resultDiv.classList.remove('hidden'); // 移除隐藏类,显示div
// 调用API发送POST请求到指定端点
const response = await fetch(`https://api.demo.top/api/reload`, {
method: 'POST', // 使用POST方法
headers: {
'Content-Type': 'application/json' // 设置请求头为JSON格式
}
});
// 将响应解析为JSON格式
const result = await response.json();
// 根据API返回的成功状态设置结果显示样式
resultDiv.className = result.success ? 'success' : 'error';
// 构建要显示的结果HTML内容
let html = '';
if (result.success) {
// 成功情况的显示内容
html += '<div class="status-line"><strong>✅ 数据重载成功</strong></div>';
html += `<div class="status-line">${result.message}</div>`;
// 如果有详细数据,显示详细信息
if (result.data) {
html += '<hr style="margin: 15px 0;">'; // 添加分隔线
html += '<div class="status-line"><strong>详细信息:</strong></div>';
html += `<div class="status-line">重载前: ${result.data.before} 条记录</div>`;
html += `<div class="status-line">重载后: ${result.data.after} 条记录</div>`;
html += `<div class="status-line">变化: ${result.data.difference > 0 ? '+' : ''}${result.data.difference} 条记录</div>`;
html += `<div class="status-line">时间: ${result.data.timestamp}</div>`;
}
} else {
// 失败情况的显示内容
html += '<div class="status-line"><strong>❌ 数据重载失败</strong></div>';
html += `<div class="status-line">${result.message}</div>`;
// 如果有错误详情,显示错误信息
if (result.error) {
html += `<div class="status-line">错误: ${result.error}</div>`;
}
}
// 将构建的HTML插入结果div
resultDiv.innerHTML = html;
} catch (error) {
// 捕获网络错误或其他异常
resultDiv.className = 'error';
resultDiv.innerHTML = `
<div class="status-line"><strong>❌ 请求失败</strong></div>
<div class="status-line">无法连接到服务器</div>
<div class="status-line">错误: ${error.message}</div>
<div class="status-line">请确保服务器正在运行</div>
`;
} finally {
// 无论成功或失败,最后都会执行这里
// 恢复按钮的可用状态
reloadBtn.disabled = false;
// 恢复按钮文字
reloadBtn.textContent = '更新数据';
}
});
});
</script>
评论 (0)