JS 事件循环机制、调用栈、堆、主线程、宏任务队列、微任务队列、缓存管理之间的关系

news/2024/11/29 1:32:23/

一、事件循环机制

你是否想过,在控制台执行代码时,为什么能立即得到响应?
实际上,底层有一套模型机制叫 事件循环,换句话说,它是一个”死循环“,
里面负责监听&执行我们写的 JS 代码,咋们暂且称为一个处理代码的容器。

事件循环负责执行代码,而执行是一套机制存在的,这里借用 MDN 的图:
请添加图片描述
下面我将一一解释每个机制的作用。

二、调用栈与堆

2.1 调用栈

当我们调用一个函数时,这个函数就会进入栈,在图上面则对应一个帧(Frame ),函数执行完后,”帧“便消失:

debugger
const foo = () => {}
foo()

请添加图片描述

我们常看到的”栈溢出“?说的就是”帧“数量太多超出限制了!
所以在执行函数时,尽量少犯这种错误,比如循环、函数递归、定时器、像这些操作都要仔细妥善处理。

2.2 堆

从图中你也看出来了,堆其实放的就是引用类型的数据,换句话说,里面就是一块内存,存放对象数据的。
请添加图片描述

三、主线程

3.1 什么是主线程?

当我们正常地执行一个函数且不加以其它修饰时,这个函数便会被放到主线程里面去执行,比如:

const foo = () => {}
foo();

主线程是按序执行的,假如有大量的函数执行,每个函数都得等前面的函数完全地执行后才能轮到它执行。
这样会存在一个阻塞问题,假设有个请求商品列表函数,响应结果等了 3s,
而函数后正好是获取用户个人头像的函数。

于是,用户的头像至少得等 3s 后才能展示出来,对于用户体验来说是不能忍受的。
换句话说,只要有阻塞行为,那就是不可取的!

为了避免阻塞行为,我们必须得将阻塞的函数放到另一种地方去执行,不能影响主线程。

这种地方就叫做 任务队列

四、宏任务队列

宏任务队列通常有这几种:

  • setTimeout/setInverval 定时器。
  • callback 回调函数。
const foo = () => console.log('Hello, I am Foo')
setTimeout(foo, 10)
const bar = () => console.log('Hello, I am Bar')
bar()
// 打印顺序是:Hello, I am Bar -> Hello I am Foo

强调下,定时器的第二个参数表示执行时间的最小单位,并不会准确的按照指定时间去执行,
也就是说,它是不稳定的,出现不稳定的因素有比如,其它宏任务还未执行或主线任务还没执行完时,
此时的 foo 就不会被调用,或者说也处于“阻塞状态”(但不影响主线程),我们来验证这点:

const now = Date.now()
console.log('当前时间:', now)
const foo = () => console.log('Hello, I am Foo. 当前花费时间(s):', (Date.now() - now) / 1000)
setTimeout(foo, 500)
while(Date.now() - now <= 2000) {}

上面的代码中,定时器指定了 500ms,但实际上过了 500ms 后根本不会立即执行,因为我们主线程还在执行 while 语句呢,换句话说,主线程优先级大于定时器。

五、微任务队列

微任务队列通常有这几种:

  • Promiseasync/awaitqueueMicrotask

微任务和宏任务概率是相同的,都是属于异步操作,但微任务队列的执行优先级大于宏任务,看例子:

Promise.resolve(() => '').then(() => console.log('Hello, p'))
setTimeout(() => console.log('Hello, s'), 0)
console.log('Hello, main')
// 将会打印:
// Hello, main
// Hello, p
// Hello, s

六、总结

  1. JS 底层有一套《事件循环》模型,说白点就是监听并执行开发人员写的 JS 代码。
  2. 执行过程时有这套机制:
    2.1 调用栈:记录函数的调用与销毁过程。
    2.2 堆:一块存放对象的数据内存。
    2.3 代码执行优先级:主线程(同步执行,会阻塞) > 微任务队列(异步执行,不阻塞) > 宏任务队列(异步执行,不阻塞)

七、缓存管理

缓存放到最后讲是因为这部分内容与上面没多大关系,这里仅顺带讲下。

首先,对于底层语言比如 C 来说,声明变量或函数是需要手动分配和释放内存的,
然而,在高级语言比如 JS/PHP/Python 中,这部分操作被自动化了。

这里我们重点关注:内存是如何被自动销毁的?,换句话说,在 JS 中,这些变量的内存垃圾回收机制是怎样的?
在刚开始时,JS 采用的第一种策略叫做 计数法

原理是,当一个变量被引用时加 1,反之减 1,当引用数等于 0 时,这个变量就可以被销毁了,我们来看下例子:

const o = { name: 'Jack'}
const o2 = o // 引用 + 1
const name = o2.name // 引用 + 2

假设 name 变量最终没有被任何地方引用,则引用 --1,o2 没人引用也 --1,最后只剩下 o,发现也没被引用,
于是这几个变量便可全回收掉。

然而这种方式存在一个问题,如果变量之间相互引用,引用值的计算规则就乱套了,来看下例子:

const o = {name: 'Jack', o2: o2} // o 引用了 o2
const o2 = { name: 'John', o: o, } // o2 引用了 o

这像不像 Mysql 或 Java 等其它语言常说的死锁概念?两者僵持不下,为了解决这问题:
JS 采取了一种新的策略叫做:标记-清除法

核心思路是,JS 定期从顶端(windows)全局对象开始从上向下查找是否有这个对象,如果获取不到这个对象,则该对象便可销毁。

从 2012 年开始,标记-清除法 开始被广泛应用,后来许多回收算法也是基于此策略进行改造的。

对于大部分 JS 开发者而言,我们可以不关系垃圾回收机制的,但是呢,知道哪些地方会造成垃圾对我们写代码和调试是有帮助的,就好比日常的丢垃圾一样,如果你不知道回收站在哪里,直接随地一扔的话会被人鄙视的!

小结:垃圾回收机制

  1. 计数法 2012 年前最初用的,后来因为相互引用问题,弃之。
  2. 标记-清除法 2012 年后开始广泛应用,解决 计数法 带来的弊端。

完!


http://www.ppmy.cn/news/239715.html

相关文章

Java数组常用方法

Java 数组提供了一系列常用的方法&#xff0c;用于操作和处理数组。以下是一些常见的数组方法&#xff1a; length&#xff1a; 返回数组的长度&#xff08;元素个数&#xff09;。 int[] numbers {1, 2, 3, 4, 5}; int length numbers.length; System.out.println(length); …

508教室使用方法

一、教室平面图 508教室的布局如下&#xff0c;重要的设备已经在图中标出。总开关、一体机和机柜。   二、使用方法 2.1 房间机器上电 进门后首先走到“总开关位置”&#xff0c;将电匝闭合。 原来的开关如图所示&#xff0c;有3组开关&#xff0c;1号组开关用于控制插座、…

继续探索Roop(单张图视频换脸)的各方面:比如喜闻乐见的“加速”

文章目录 &#xff08;一&#xff09;Roop项目的特点&#xff08;二&#xff09;Roop也能加速***&#xff08;三&#xff09;Roop更新和依赖&#xff08;3.1&#xff09;飞速更新&#xff08;3.2&#xff09;依赖问题&#xff08;3.3&#xff09;需要CUDA么 前两天写了&#x1…

2020-10-24

升内存&#xff0c;联想IdeaPad330C-15IKB拆机图解 工具&#xff1a;小螺丝刀&#xff0c;银行卡一张&#xff08;类似的硬质卡片&#xff0c;公交车卡之类的都可以&#xff09; 先拧掉小螺丝&#xff0c;再用银行卡撬开四边就可以啦 如果实在心里没谱&#xff0c;就像第一次的…

低压差低功耗LDO低ETA5071是应用的理想电源,非常适合LOT、可穿戴设备和指纹锁应用

刘西西15914002706 微信同号 产品描述 ETA5071是一个固定输出&#xff0c;低压差&#xff08;LDO&#xff09;低功耗线性电压调节器&#xff0c;具有超低待机电流低至1UA。它可以承受高达7V的输入电压和输出300mA。因此&#xff0c;ETA5071是低功耗应用的理想想电源&…

电脑开机显示checking media解决方法

1、进入pe界面&#xff0c;打开diskgenius分区工具&#xff0c;将硬盘重新分区&#xff0c;分成mbr格式 2、然后进bios&#xff0c;切换到security选项&#xff0c;选择seurce boot回车进入下一子菜单 3、然后选择seurce boot&#xff0c;设置为disabled 4、接着切换到start…

330UF16V 10*7.7片式铝电解电容封装

合粤电子HD系列7.7mm高量产规格&#xff1a; 合粤电子新推出10*7.7mm高HD系列高频低阻抗贴片铝电解电容适用于通信设备、电脑及周边配件、LCD电视机、便携式DVD播放机、GPS定位导向、车载TV/DVD/RADIO、高清电视(包括数字机顶盒)、LCD、车载DVD&#xff0c;机顶盒&#xff0c;…

联想卡在logo界面_电脑开机一直停在lenovo界面的解决方法

现在不管是学习还是工作我们都离不开电脑&#xff0c;但近日有的用户却反映说自己的电脑出现了开机一直停在lenovo界面的情况&#xff0c;不知道怎么解决&#xff0c;很是影响自己的使用。所以今天小编为大家整理的就是关于电脑开机一直停在lenovo界面的解决方法。 解决方法如下…