当前位置:首页 > JavaScript

js实现eventloop

2026-02-01 13:49:30JavaScript

Event Loop 的基本概念

Event Loop 是 JavaScript 运行时环境的核心机制,用于处理异步任务和执行顺序。它确保非阻塞 I/O 操作能够高效执行,同时保持单线程的特性。

调用栈(Call Stack)

调用栈是 JavaScript 执行同步代码的地方。函数调用会被压入栈中,执行完毕后弹出。如果栈中出现长时间运行的任务,会导致阻塞。

function foo() {
  console.log('foo');
}
function bar() {
  foo();
  console.log('bar');
}
bar();
// 输出顺序: foo -> bar

任务队列(Task Queue)

异步操作(如 setTimeoutsetInterval、I/O 回调)完成后,会将回调函数放入任务队列。Event Loop 在调用栈为空时,从任务队列中取出任务执行。

js实现eventloop

console.log('Start');
setTimeout(() => console.log('Timeout'), 0);
console.log('End');
// 输出顺序: Start -> End -> Timeout

微任务队列(Microtask Queue)

微任务队列优先级高于任务队列,通常包括 Promise 的回调、MutationObserver 等。每次调用栈清空后,Event Loop 会先处理所有微任务,再处理任务队列。

console.log('Start');
Promise.resolve().then(() => console.log('Promise'));
setTimeout(() => console.log('Timeout'), 0);
console.log('End');
// 输出顺序: Start -> End -> Promise -> Timeout

Event Loop 的执行流程

  1. 执行同步代码,填充调用栈。
  2. 遇到异步任务时,将回调注册到对应队列(宏任务或微任务)。
  3. 调用栈清空后,检查微任务队列并执行所有微任务。
  4. 执行一个宏任务(如 setTimeout 回调)。
  5. 重复步骤 3-4,直到所有队列为空。

代码示例分析

console.log('Script start');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve()
  .then(() => {
    console.log('Promise 1');
  })
  .then(() => {
    console.log('Promise 2');
  });

console.log('Script end');

输出顺序:

js实现eventloop

  1. Script start
  2. Script end
  3. Promise 1
  4. Promise 2
  5. setTimeout

常见异步操作分类

  • 宏任务(Macrotasks): setTimeout, setInterval, I/O, UI rendering
  • 微任务(Microtasks): Promise, process.nextTick (Node.js), MutationObserver

Node.js 中的 Event Loop

Node.js 的 Event Loop 分为多个阶段,每个阶段处理特定类型的任务:

  1. Timers: 执行 setTimeoutsetInterval 回调。
  2. I/O Callbacks: 执行大多数 I/O 相关的回调。
  3. Idle/Prepare: 内部使用。
  4. Poll: 检索新的 I/O 事件。
  5. Check: 执行 setImmediate 回调。
  6. Close Callbacks: 执行关闭事件的回调(如 socket.on('close'))。
setImmediate(() => console.log('setImmediate'));
setTimeout(() => console.log('setTimeout'), 0);
// 输出顺序可能交替,取决于上下文

避免阻塞 Event Loop

长时间运行的同步代码会阻塞 Event Loop,导致异步任务无法及时处理。解决方案包括:

  • 将计算密集型任务拆分为小块,使用 setTimeoutsetImmediate 分步执行。
  • 使用 Web Workers 或子进程(Node.js)处理耗时任务。
// 错误示例:阻塞 Event Loop
for (let i = 0; i < 1e9; i++) { /* 长时间运算 */ }

// 改进:分块执行
function chunkedTask(start, end) {
  if (start >= end) return;
  setTimeout(() => {
    for (let i = start; i < Math.min(start + 1e6, end); i++) { /* 处理小块 */ }
    chunkedTask(start + 1e6, end);
  }, 0);
}

总结

Event Loop 通过调用栈、任务队列和微任务队列的协作,实现了 JavaScript 的异步非阻塞执行。理解其运行机制有助于编写高效的异步代码,避免常见性能问题。

标签: jseventloop
分享给朋友:

相关文章

js实现轮播图

js实现轮播图

轮播图实现方法 基础HTML结构 <div class="slider"> <div class="slides"> <img src="image1.jpg…

js实现vue

js实现vue

Vue.js 简介 Vue.js 是一个渐进式 JavaScript 框架,用于构建用户界面。其核心库专注于视图层,易于与其他库或现有项目整合。 实现 Vue.js 的基本步骤 安装 Vue.…

js实现跳转

js实现跳转

使用 window.location 跳转 通过修改 window.location.href 实现页面跳转,这是最常用的方法。 window.location.href = 'https:/…

js实现计算器

js实现计算器

实现基础计算器功能 使用JavaScript创建一个基础计算器需要处理数字输入、运算符逻辑和结果显示。以下是一个简单的实现示例: let currentInput = '0'; let previ…

js实现文件下载

js实现文件下载

使用 a 标签下载文件 通过动态创建 a 标签并设置 download 属性实现文件下载。适用于已知文件 URL 或 Blob 数据的情况。 function downloadFile(url,…

原生js实现轮播图

原生js实现轮播图

基本结构搭建 HTML部分需要包含轮播图容器、图片列表及导航按钮。结构示例如下: <div class="slider-container"> <div class="slid…