【EventLoop】从理解到精通事件循环

前言

什么是事件循环/EventLoop?

EventLoop JS 代码的执行分为同步任务代码和异步任务代码当碰到同步代码时,直接在执行栈中执行,当碰到异步任务并且时机符合时(例如定时器的时间到了),就把异步代码添加到任务队列中当执行栈中的同步代码执行完毕后,才去任务队列中把异步代码拿到执行栈中执行其实这种返回轮询任务队列的过程就是 Event Loop;

什么是单线程?

JS 是单线程的,也就是说执行 JS 代码的线程只有一个( JS 引擎线程),我们也叫主线程,那为什么浏览器可以同时执行异步任务呢,因为浏览器的渲染进程是多线程的,当需要执行异步任务的时候,浏览器会帮我们启动另外一个线程来执行该任务! 浏览器中还有定时器线程、HTTP请求线程等,这些任务不是用来执行 JS 代码的,主要用来执行其他的一些任务!

比如主线程(JS 引擎线程)中碰到AJAX请求,就把这个任务交给线程HTTP请求线程去真正的发送请求,等到请求回来了之后,再将callback里需要执行的JS回调函数,交给JS引擎线程去执行,也就是说浏览器才是真正执行发送请求这个任务的角色,而JS只是负责执行最后的回调处理!

PS:`事件循环是js代码单线程语言执行机制,编译器是按照事件循环的机制来执行的; (1)先解析默认script宏任务,

(2)判断代码是同步还是异步,

(3)如果是同步,立即执行,

(4)如果是异步,就放入异步队列,微任务放入微任务队列,宏任务放入宏任务队列;

(5)当前排队所有的同步都执行完毕,开始执行异步,从微队列开始依次执行。

小试牛刀(练习一)

源代码如下:

javascript 复制代码
// 练习一 : 小试牛刀
setTimeout(function() {
  console.log(1)
}, 0);

new Promise(function executor(resolve) {
  console.log(2);
  for( var i=0 ; i<10000 ; i++ ) {
    i == 9999 && resolve();
  }
  console.log(3);
}).then(function() {
  console.log(4);
});
console.log(5);

分析打印结果如下:

javascript 复制代码
// 练习一 : 小试牛刀
setTimeout(function() {
  // 异步(宏任务 #1)
  console.log(1)
}, 0);

new Promise(function executor(resolve) {
  // 同步任务 #1
  console.log(2);
  for( var i=0 ; i<10000 ; i++ ) {
    i == 9999 && resolve();
  }
  // 同步任务 #2
  console.log(3);
}).then(function() {
  // 异步(微任务 #1)
  console.log(4);
});
  // 同步任务 #3
console.log(5);

// 依次打印结果:  2  3  5  4  1

PS: return Promise.resolve(undefined).then(); // 默认会返回这么一句话

渐入佳境(练习二)

源代码如下:

javascript 复制代码
// 练习二: 渐入佳境
setTimeout(() => {
  new Promise(resolve => {
      resolve();
  }).then(() => {
      console.log('test');
  });
    console.log(4);
}); 

new Promise(resolve => {
  resolve();
  console.log(1)
}).then(() => {
  console.log(3);
  Promise.resolve().then(() => {
    console.log('before timeout');
  // return Promise.resolve(undefined); // 默认会返回这么一句话
}).then(() => {
  Promise.resolve().then(() => {
    console.log('also before timeout')
    })
  })
})
console.log(2);

分析结果如下:

javascript 复制代码
  // 练习二: 渐入佳境
setTimeout(() => {
  // 宏 #1
  new Promise(resolve => {
      resolve();
  }).then(() => {
    // 微 #5
      console.log('test');
  });
  // 同 #3
    console.log(4);
}); 

new Promise(resolve => {
  // 同 #1
  resolve();
  // 微 #1
  console.log(1)
}).then(() => {
  // 微 #2
  console.log(3);
  Promise.resolve().then(() => {
  // 微 #3
    console.log('before timeout');
  // return Promise.resolve(undefined); // 默认会返回这么一句话
}).then(() => {
  Promise.resolve().then(() => {  
    // 微 #4
    console.log('also before timeout')
    })
  })
})
// 同 #2
console.log(2);

// 依次打印结果:  1 2 3 before timeout also before timeout  4  test

游刃有余(练习三)

源代码如下:

scss 复制代码
// 练习三: 游刃有余
setTimeout(function() {
    console.log(0);
});

new Promise((resolve, reject) => {
    console.log(1);
    resolve();
}).then(() => {
    console.log(2);
    new Promise((resolve, reject) => {    
        console.log(3);
        resolve();
    }).then(() => {
        console.log(4);
    }).then(() => {
        console.log(5);
    });
}).then(() => {
    console.log(6);
});

new Promise((resolve, reject) => {
    console.log(7);
    resolve();
}).then(() => {
    console.log(8);
});

分析结果如下:

scss 复制代码
// 练习三: 游刃有余
setTimeout(function() {
    // 宏 #1
    console.log(0);
});

new Promise((resolve, reject) => {
  // 同 #1
    console.log(1);
    resolve();
}).then(() => {
  // 微 #1
    console.log(2);
    new Promise((resolve, reject) => {    
        console.log(3);
        resolve();
    }).then(() => {
      // 微 #3
        console.log(4);
    }).then(() => {
      // 微 #5
        console.log(5);
    });
}).then(() => {
  // 微 #4
    console.log(6);
});

new Promise((resolve, reject) => {
  // 同 #2
    console.log(7);
    resolve();
}).then(() => {
  // 微 #2
    console.log(8);
});

结尾

在日益竞争的软件开发领域,掌握异步编程和事件循环的知识将使您在开发高性能、高可用性的应用程序上更加游刃有余。不断学习和实践是精通这些技术的关键,希望您能在实际项目中尝试应用这些概念,从而不断完善自己的技术水平。 逐字稿: 事件循环是js代码单线程语言执行机制,编译器是按照事件循环的机制来执行的;

(1)先解析默认script宏任务,

(2)判断代码是同步还是异步,

(3)如果是同步,立即执行,

(4)如果是异步,就放入异步队列,微任务放入微任务队列,宏任务放入宏任务队列;

(5)当前排队所有的同步都执行完毕,开始执行异步,从微队列开始依次执行。

相关推荐
事圆则缓1 分钟前
Flutter 状态管理框架对比(五):GetX 的响应式、依赖注册与生命周期
前端·javascript·flutter
广州智造1 小时前
Radioss复合材料使用的单元属性
前端·设计·cad·建模·cae·radioss
张宏宇1 小时前
我把微软开源的 tgrep 做成了本地版 GitHub Code Search:45,629 个文件里搜一次 10ms
前端·后端
huakoh1 小时前
MCP 调用超时后别急着重试:三步读回分清执行状态
前端
打工仔折腾 AI1 小时前
把模型切换交给平台:用蓝耘智能路由搭建商品评论分析工具
java·服务器·前端·后端·python·性能优化·ai agent 实战
不可能片场2 小时前
Electron 发布标题的冒号 击穿命令行解析
前端·electron
500842 小时前
React Native for OpenHarmony 实战:三方库 react-native-crypto-js 的鸿蒙化适配指南
javascript·react native·性能优化·electron·harmonyos
reeswell2 小时前
我开源了 inspect-devtools —— 让 AI 终于能"看见"你屏幕上的组件
前端·人工智能
Yuhano2 小时前
W3. 实现Agent工具调用引擎
前端·aigc·ai编程
flash俊杰2 小时前
第三节 基于 Vue 3 的领域模型架构——Schema 驱动的低代码后台实战
前端