JS同步与异步概念及区别
同步(Synchronous)
-
概念
- 代码按顺序逐行执行,前一个操作完成后,才能执行下一个操作。
- 如果遇到耗时操作(如复杂计算、文件读取等),后续代码必须等待当前操作完成。
-
特点
- 阻塞性:同步代码会阻塞主线程,导致后续代码无法立即执行。
- 简单性:代码顺序直观,易于理解。
-
示例
console.log("Step 1"); // 立即执行 calculateHeavyTask(); // 假设这是一个耗时同步函数 console.log("Step 2"); // 必须等待上一步完成
异步(Asynchronous)
-
概念
- 代码不等待耗时操作完成,而是先继续执行后续代码。
- 耗时操作完成后,通过回调函数、Promise等机制通知程序处理结果。
-
特点
- 非阻塞性:主线程不被阻塞,用户界面保持响应。
- 复杂性:需要处理回调嵌套(如回调地狱),但可通过Promise/async/await优化。
-
示例
console.log("Start"); setTimeout(() => { console.log("Async operation done"); // 延迟后执行 }, 1000); console.log("End"); // 立即执行,无需等待setTimeout // 输出顺序:Start → End → Async operation done
关键区别
特性 | 同步 | 异步 |
---|---|---|
执行顺序 | 顺序执行,严格阻塞 | 非阻塞,后续代码立即执行 |
适用场景 | 简单、即时操作 | I/O操作、网络请求、定时任务 |
性能影响 | 可能导致界面卡顿 | 提升响应速度和性能 |
实现方式 | 普通函数调用 | 回调函数、Promise、async/await、事件监听 |
底层机制:事件循环(Event Loop)
JavaScript通过事件循环管理异步任务:
- 调用栈(Call Stack):执行同步代码。
- 任务队列(Task Queue):存放异步完成的回调(如
setTimeout
、DOM事件)。 - 微任务队列(Microtask Queue):存放优先级更高的回调(如
Promise.then()
、MutationObserver
)。 - 执行顺序:
- 同步代码(调用栈)→ 清空微任务队列 → 取出一个宏任务执行 → 重复循环。
总结
- 同步:代码顺序执行,简单但可能阻塞。
- 异步:非阻塞执行,适合耗时操作,依赖事件循环管理。
- 选择依据:根据是否需要等待操作结果(如用户输入、API响应)决定使用同步或异步。
通过合理使用异步(如Promise
、async/await
),可以在保持代码可读性的同时,优化性能和用户体验。