JavaScript 中的同步异步
JavaScript中的同步与异步编程完全解析
目录
1. 同步与异步的区别
1.1. 同步编程
console.log("步骤1");
console.log("步骤2");
console.log("步骤3");
// 严格按顺序执行,输出顺序永远固定
// 输出顺序:步骤1 -> 步骤2 -> 步骤3
特点:
- 阻塞式执行
- 代码顺序即执行顺序
- 简单易理解
- 可能造成界面卡顿
1.2. 异步编程
console.log("开始");
setTimeout(() => console.log("异步操作"), 0);
console.log("结束");
// 输出顺序:开始 -> 结束 -> 异步操作
特点:
- 非阻塞式执行
- 通过回调机制处理结果
- 适合处理耗时操作
- 执行顺序不可预测
2. JavaScript执行机制
2.1. 运行时架构
- 调用栈(Call Stack):同步代码执行场所
- Web APIs:浏览器提供的异步功能(setTimeout、AJAX等)
- 任务队列(Task Queue):存放异步回调
- 事件循环(Event Loop):协调调用栈与任务队列
2.2. 执行流程示例
console.log("脚本启动");
setTimeout(function timeout1() {
console.log("定时器1");
}, 0);
fetch('https://api.example.com/data')
.then(response => console.log("网络请求完成"));
console.log("脚本结束");
/*
典型输出顺序:
脚本启动
脚本结束
网络请求完成
定时器1
*/
3. 常见的异步操作
3.1. 定时器
// setTimeout基本用法
setTimeout(() => {
console.log('延迟执行');
}, 1000);
// setInterval示例
let counter = 0;
const timer = setInterval(() => {
console.log(`第${++counter}次执行`);
if(counter === 5) clearInterval(timer);
}, 1000);
3.2. 事件监听
document.getElementById('myButton').addEventListener('click', () => {
console.log('按钮被点击');
});
3.3. Promise
function asyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ?
resolve('成功') :
reject(new Error('失败'));
}, 1000);
});
}
asyncOperation()
.then(console.log)
.catch(console.error);
3.4. async/await
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('请求失败:', error);
}
}
4. 最佳实践
- 避免回调地狱
// 错误示例
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
// 嵌套层级过深
});
});
});
// 正确方式(使用Promise链)
getData()
.then(a => getMoreData(a))
.then(b => getMoreData(b))
.then(c => {/* 处理数据 */})
.catch(handleError);
- 错误处理
// Promise的错误捕获
fetch('/api/data')
.then(response => response.json())
.catch(error => console.error('请求失败:', error));
// async/await的错误处理
async function loadData() {
try {
const data = await fetchData();
} catch (err) {
console.error(err);
}
}
- 并行处理
// 使用Promise.all
const [users, posts] = await Promise.all([
fetch('/api/users'),
fetch('/api/posts')
]);
// 并行执行不相关操作
await Promise.all([
logAnalytics(),
updateUserStatus(),
prefetchResources()
]);
5. 总结
JavaScript的异步编程经历了多个发展阶段:
1. 回调函数 -> 2. Promise -> 3. Generator -> 4. async/await
关键要点:
- 理解事件循环机制
- 优先使用async/await语法
- 始终处理错误情况
- 避免阻塞主线程
- 合理使用微任务(Promise)和宏任务(setTimeout)
掌握异步编程是必经之路,合理运用可以显著提升应用性能和用户体验。