JavaScript 中的同步异步

38

JavaScript中的同步与异步编程完全解析

目录

  1. 同步与异步的区别
  2. JavaScript执行机制
  3. 常见的异步操作
  4. 最佳实践
  5. 总结

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. 运行时架构

  1. 调用栈(Call Stack):同步代码执行场所
  2. Web APIs:浏览器提供的异步功能(setTimeout、AJAX等)
  3. 任务队列(Task Queue):存放异步回调
  4. 事件循环(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. 最佳实践

  1. 避免回调地狱
// 错误示例
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);
  1. 错误处理
// 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);
  }
}
  1. 并行处理
// 使用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)

掌握异步编程是必经之路,合理运用可以显著提升应用性能和用户体验。