当前位置: 首页 > ds >正文

JS 事件循环详解

JS 事件循环详解

文章目录

  • JS 事件循环详解
    • 一、JS 的单线程模型与异步机制
    • 二、事件循环的核心组件
      • 1. 执行栈(Call Stack)
      • 2. 任务队列(Task Queue)
      • 3. Web APIs
    • 三、事件循环的执行流程
    • 四、任务类型详解
      • 1. 宏任务(Macrotask)
      • 2. 微任务(Microtask)
    • 五、经典执行顺序示例
    • 六、实际应用场景
      • 1. 定时任务控制
      • 2. Promise 异步流程
      • 3. DOM 事件优化
    • 七、常见误区与最佳实践
      • 1. 不要阻塞事件循环
      • 2. 微任务嵌套陷阱
      • 3. 合理使用任务优先级

一、JS 的单线程模型与异步机制

JS 是一种单线程语言,这意味着它只有一个主线程(执行栈)来处理所有任务。这种设计避免了多线程环境中的复杂同步问题,但也带来了一个挑战:如何防止长时间运行的代码阻塞整个程序?

解决方案是将代码分为:

  • 同步代码:由 JS 引擎直接执行
  • 异步代码:交给宿主环境(浏览器/Node.js)处理

二、事件循环的核心组件

1. 执行栈(Call Stack)

  • 用于存储同步任务的执行上下文
  • 遵循后进先出(LIFO)原则
  • 当函数执行时会被推入栈顶,执行完毕后弹出

2. 任务队列(Task Queue)

  • 宏任务队列(Macrotask Queue)
  • 微任务队列(Microtask Queue)

3. Web APIs

  • 浏览器提供的异步API(setTimeout、DOM事件等)
  • Node.js 中的 I/O 操作等

三、事件循环的执行流程

  1. 执行同步代码:执行栈中的任务依次执行

  2. 处理微任务

    • 执行栈清空后,立即执行所有微任务
    • 微任务执行期间产生的新微任务会继续执行
  3. 渲染更新(浏览器环境)

  4. 取一个宏任务执行

  5. 重复循环

    在这里插入图片描述

四、任务类型详解

1. 宏任务(Macrotask)

来源示例
setTimeout/setIntervalsetTimeout(fn, 0)
I/O 操作文件读写、网络请求
UI 渲染(浏览器)
事件回调click, scroll
setImmediate(Node.js 特有)

特点:

  • 每次事件循环只执行一个宏任务
  • 优先级低于微任务

2. 微任务(Microtask)

来源示例
Promise.then()/.catch()
MutationObserverDOM 变更观察
process.nextTick(Node.js 特有,优先级最高)

特点:

  • 在当前宏任务结束后立即执行
  • 会清空整个微任务队列
  • 优先级高于宏任务

五、经典执行顺序示例

console.log('1. 同步代码开始');setTimeout(() => {console.log('6. 宏任务1 - setTimeout');Promise.resolve().then(() => {console.log('7. 微任务3 - Promise');});
}, 0);Promise.resolve().then(() => {console.log('3. 微任务1 - Promise');return Promise.resolve();
}).then(() => {console.log('4. 微任务2 - Promise');
});console.log('2. 同步代码结束');// 输出顺序:
// 1. 同步代码开始
// 2. 同步代码结束
// 3. 微任务1 - Promise
// 4. 微任务2 - Promise
// 6. 宏任务1 - setTimeout
// 7. 微任务3 - Promise

六、实际应用场景

1. 定时任务控制

// 动画帧控制
function animate() {// 动画逻辑requestAnimationFrame(animate); // 比setTimeout更适合动画
}
animate();// 轮询检查
function poll() {fetch('/api/status').then(checkStatus).then(() => setTimeout(poll, 5000));
}

2. Promise 异步流程

function loadData() {return fetch('/api/data').then(response => response.json()).then(data => {// 处理数据return processData(data);}).catch(error => {// 错误处理console.error(error);});
}

3. DOM 事件优化

// 防抖处理高频事件
function debounce(fn, delay) {let timer;return function() {clearTimeout(timer);timer = setTimeout(() => fn.apply(this, arguments), delay);};
}window.addEventListener('scroll', debounce(() => {// 处理滚动逻辑
}, 100));

七、常见误区与最佳实践

1. 不要阻塞事件循环

// 错误示范:同步计算阻塞UI
function heavyCalc() {let result = 0;for (let i = 0; i < 1000000000; i++) {result += Math.sqrt(i);}return result;
}// 正确做法:分片处理
async function chunkedHeavyCalc() {let result = 0;for (let i = 0; i < 100000000; i += 100000) {result += await chunkCalc(i, Math.min(i + 100000, 100000000));// 允许浏览器渲染await new Promise(resolve => requestAnimationFrame(resolve));}return result;
}

2. 微任务嵌套陷阱

// 可能导致无限循环
function microtaskLoop() {Promise.resolve().then(microtaskLoop);
}
// microtaskLoop(); // 不要这样做!

3. 合理使用任务优先级

// 需要立即执行的任务使用微任务
function urgentTask(callback) {Promise.resolve().then(callback);
}// 不紧急的任务使用宏任务
function backgroundTask(callback) {setTimeout(callback, 0);
}
http://www.xdnf.cn/news/10120.html

相关文章:

  • 告别重复 - Ansible 配置管理入门与核心价值
  • 在 Linux 上安装 Minikube:轻松搭建本地 Kubernetes 单节点集群
  • 项目管理工具Maven
  • java/mysql/ES下的日期类型分析
  • 【FlashRAG】本地部署与demo运行(二)
  • PHP7内核剖析 学习笔记 第九章 PHP基础语法的实现
  • [特殊字符] xbatis 一款好用 ORM 框架 1.8.8-M2 发布,节省 1/3 代码和时间的框架!!!
  • Drawio编辑器二次开发
  • 【pytorch学习】土堆pytorch学习笔记2
  • 【Linux】权限相关指令
  • Axure疑难杂症:中继器新增数据时如何上传并存储图片(玩转中继器)
  • 【仿生机器人系统设计】涉及到的伦理与安全问题
  • 数据基座觉醒!大数据+AI如何重构企业智能决策金字塔(上)
  • 代码随想录打卡|Day53 图论(Floyd 算法精讲 、A * 算法精讲 (A star算法)、最短路算法总结篇、图论总结 )
  • 历年武汉大学计算机保研上机真题
  • 服务器液冷:突破散热瓶颈,驱动算力革命的“冷静”引擎
  • 美国服务器文件系统的基本功能和命令
  • ansible-playbook 进阶 接上一章内容
  • dart实现单client连接的grpc server (以ip地址作判断)
  • Yum配置第三方源与本地源详解
  • 日常--OBS+mediamtx实现本地RTMP推流环境搭建(详细图文)
  • RPG17.蓝图函数库与轻重攻击连击
  • C++ 5.29 dddd
  • 【深度剖析】义齿定制行业数字化转型模式创新研究(上篇2:痛点和难点分析)
  • AI智能监控系统:赋能厂区安全管理的数智化革新
  • [Dify] 如何应对明道云API数据过长带来的Token超限问题
  • OAuth协议中的Token、Ticket
  • (NAT64)IPv6网络用户访问IPv4网络服务器(动态映射方式)
  • Linux服务器时间同步——Chronyd
  • MyBatis动态SQL