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

【JS事件循环机制event-loop】

目录

    • 0、总结
    • 1、Event-Loop 概念
    • 2、宏任务-微任务
    • 3、事件循环执行机制
    • 4、调用栈
    • 5、示例

0、总结

  • Tasks execute in order, and the browser may render between them 【宏任务按序执行,浏览器可以在它们之间进行渲染】
  • Microtasks execute in order, and are executed:【微任务按序执行,执行与如下时刻:】
    • after every callback, as long as no other JavaScript is mid-execution【每次回调后,只要没有其他 JS 处于执行过程中】
    • at the end of each task【在每次宏任务的末尾】
# 进程是 CPU 资源分配的最小单位(是能拥有资源和独立运行的最小单位);
# 线程是 CPU 调度和分派的基本单位,共享进程的内存空间和资源,每个线程有自己的栈空间和程序计数器;
# 浏览器每打开一个 tab 页,就是开了一个进程;

1、Event-Loop 概念

  • 事件循环是浏览器或 node 环境执行 js 代码的一种规则

  • 同步任务都在 JS 引擎线程(主线程)上执行,形成一个执行栈

  • 事件触发线程管理着一个任务队列(宏任务队列),异步任务有了运行结果,就在任务队列中放置一个事件

  • 什么时候用到定时器触发线程?当使用setTimeoutsetInterval时,需要定时器触发线程计时,计时完成后就会将特定的事件推入事件队列中。

    • 为什么要单独的定时器触发线程?因为 JavaScript 引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确,因此很有必要单独开一个线程用来计时。
  • 一旦执行栈中的所有同步任务执行完毕(此时 JS 引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。

    为什么有时候setTimeout推入的事件不能准时执行?因为可能在它推入到事件列表时,主线程还不空闲,正在执行其它代码,所以自然有误差。

    • 主线程运行时会产生执行栈,栈中的代码调用某些 api 时,它们会在事件队列中添加各种事件(当满足触发条件后,如 ajax 请求完毕)
    • 而栈中的代码执行完毕,就会读取事件队列中的事件,去执行那些回调
    • 如此循环在这里插入图片描述

2、宏任务-微任务

  • 好文章:Tasks,microtasks,queues and schedules

  • js 代码分为两类:同步代码、异步代码

  • 异步代码又分为:宏任务(macrotask)、微任务(microtask) ,在 ECMAScript 中macrotask称为taskmicrotask称为jobs

  • 浏览器会在一个task执行结束后,在下一个task执行开始前,对页面进行重新渲染

  • microtask 微任务都是添加到微任务队列(Job Queues)中,等待当前 macrotask 执行完毕后执行,而这个队列由 JS引擎线程 维护

    任务类别
    事件宏任务
    setTimeout宏任务
    setInterval宏任务
    setImmediate(Node 独有)宏任务
    requestAnimationFrame(浏览器独有)宏任务
    网络请求宏任务
    fs.readFile()宏任务
    UI rendering(浏览器独有)宏任务
    Promise.then()------微任务
    async/await------微任务
    process.nextTick(Node 独有)------微任务
    Object.observe------微任务
    MutationObserve------微任务

3、事件循环执行机制

  • 进入 script 标签,就进入到第一次事件循环(可看作一个宏任务开始)

  • 遇到同步代码立即执行

  • 遇到宏任务放到宏任务队列

  • 遇到微任务放到微任务队列

  • 执行完所有同步代码

  • 执行微任务

  • 微任务执行完毕,本次主线程执行栈清空,开始检查渲染,然后 GUI 线程接管渲染

  • 渲染完毕后,JS引擎线程继续接管,寻找下一个宏任务,重复上述步骤,这种重复不断的机制,就叫做事件循环

    我们在一个微任务中使用 setTimeout() 函数添加一个宏任务,那么这个新的宏任务会在当前微任务执行完毕后立即执行,而不是等待当前宏任务执行完毕再执行。

在这里插入图片描述

4、调用栈

  • 调用栈 call stack 也叫执行栈,记录了当前执行的上下文 context 和函数调用链;
  • 所有函数想要执行就必须经过调用栈,因为调用栈可以理清词法环境、变量环境等;
  • 当 js 引擎执行一个函数时,它会将函数的调用信息添加到调用栈的顶部,并在执行完该函数后从调用栈中弹出该函数的信息。如果该函数调用了其他函数,那么这些函数也会依次被添加到调用栈中,并在执行完后弹出。在函数执行期间,调用栈会保持不断增长和收缩的状态。

5、示例

async function async1() {console.log(111) //1await async2() //await会阻塞它下一行的代码await async3() //异步代码中的微任务1,先挂起console.log('async111 end') //7 微任务3 等async3执行完毕后进入任务队列
}
async function async2() {console.log('async222 end') //2
}
async function async3() {console.log('async333 end') //5
}
async1()
setTimeout(() => {//异步代码中的宏任务1,先挂起console.log('setTimeout') //9
}, 0)
new Promise((resolve) => {console.log('Promise') //3resolve()
}).then(() => {//异步代码中的微任务2,先挂起console.log('Promise111') //6}).then(() => {//异步代码中的微任务4,先挂起  前一个.then的回调函数执行后被进入任务队列console.log('Promise222') //8})
console.log('end') //4

在这里插入图片描述

http://www.xdnf.cn/news/191071.html

相关文章:

  • Rmarkdown输出为pdf的方法与问题解决
  • 数字图像处理 -- 眼底图像血管分割方法
  • 后缀数组~
  • 聊一聊接口自动化测试的稳定性如何保障
  • 在 IDEA 中写 Spark 程序:从入门到实践
  • 反向代理、负载均衡与镜像流量:原理剖析、区别对比及 Nginx 配置实践
  • 2025医疗领域AI发展五大核心趋势与路线研究
  • 在Linux系统中安装MySQL,二进制包版
  • 第十二节:性能优化高频题-shallowRef/shallowReactive使用场景
  • 云原生--核心组件-容器篇-7-Docker私有镜像仓库--Harbor
  • 【计网】认识跨域,及其在go中通过注册CORS中间件解决跨域方案,go-zero、gin
  • yolov8+kalman 实现目标跟踪统计人流量
  • redis+lua+固定窗口实现分布式限流
  • 八大排序——直接插入排序/希尔排序
  • Spring Cloud初探之自定义负载均衡策略(五)
  • 让数据优雅落地:用 serde::Deserialize 玩转结构体实体
  • CasaOS上部署1Panel开源运维面板远程在线访问配置实操指南
  • K8s新手系列之K8s中的资源
  • 【杂谈】-人工智能驱动的网络安全威胁:新一代网络钓鱼
  • Azure 数字孪生是什么?
  • ​​HTTP vs HTTPS:传输协议的安全演进与核心差异​
  • 8.Android(通过Manifest配置文件传递数据(meta-data))
  • 近地卫星网络 (Low Earth Orbit Satellite Networks)入门学习笔记
  • Transformer数学推导——Q26 推导多语言Transformer中语言间注意力共享的参数效率公式
  • C语言----操作符详解(万字详解)
  • python 线程池顺序执行
  • 二叉树的所有路径(回溯算法基础)
  • 深度学习---Pytorch概览
  • 3D模型文件格式之《DAE格式介绍》
  • [LeetCode 438/567] 找到字符串中所有字母异位词/字符串的排列(滑动窗口)