【说说你对事件循环event loop的理解】

简介: 【说说你对事件循环event loop的理解】

第一点:JavaScript是一门单线程的语言,意味着同一时间内只能做一件事情,但是并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环

第二点:所有的任务都分为同步任务、异步任务

同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行

异步任务:ajax网络请求、setTimeout定时器函数

同步任务和异步任务流程图如下:

21ca98f810cc4751b19d4a814b007618.png

从上面的图中可以看到:

同步任务进⼊主线程,即主执⾏栈,异步任务进⼊任务队列,主线程内的任务执 ⾏完毕为空,会去任务队列读取对应的任务,推⼊主线程执⾏。那么上述过程的不断重复就称为事件循环

首先我们来说一下微任务和宏任务

首先来看一段代码:

console.log(1)
setTimeout(()=>{
 console.log(2)
}, 0)
new Promise((resolve, reject)=>{
 console.log('new Promise')
 resolve()
}).then(()=>{
 console.log('then')
})
console.log(3)
按照我们上面的流程图那么我们分析的:
console.log(1):是一个同步任务,放在主线程中进行执行
setTimeOut():属于异步任务。放到Event Table,经过0秒后控制台输出2,回调推入Event Queue中
new Promise属于同步任务,放在主线程中直接执行,一旦创建就会执行
.then:属于异步任务,放在主线程中进行执行
那么分析的结果是:1  newPrimise 3 2 then
但是实际上的结果是:1 newPromise 3 then 2
那么我们分析的和正确的答案出现的不同的是在于:异步任务的执行顺序
那么队列是“先进先出”的数据结构,排在前面的事件会优先被主线程读取
我们举的例子是setTimeout回调事件是先进的队列,按道理来说应该是.then先执行,
但结果是setTimeout先执行,
最关键的原因是因为异步任务还分为微任务和宏任务

微任务:

⼀个需要异步执⾏的函数,执⾏时机是在主函数执⾏结束之后、当前宏任务结束之前

常⻅的微任务有:

1.Promise.then

2.MutaionObserver

3.Object.observe(已废弃;Proxy 对象替代)

4.process.nextTick(Node.js)

宏任务:

宏任务的时间粒度⽐较⼤,执⾏的时间间隔是不能精确控制的,对⼀些⾼实时性的需求就不太符合

常⻅的宏任务有:

1.script (可以理解为外层同步代码)

2.setTimeout/setInterval

3.UI rendering/UI事件

4.postMessage、MessageChannel

5.setImmediate、I/O(Node.js)

c2aba382b3a144a6b236986da4b0ac48.png

按照上图的流程它的执行机制是:

执行一个宏任务,如果遇到微任务就将他放到微任务的事件队列中,当前宏任务执行完之后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完毕

所以我们上面的那个执行结果是:

遇到 console.log(1) ,直接打印 1

遇到定时器,属于新的宏任务,留着后⾯执⾏

遇到 new Promise,这个是直接执⾏的,打印 'new Promise'

.then 属于微任务,放⼊微任务队列,后⾯再执⾏

遇到 console.log(3) 直接打印 3

好了本轮宏任务执⾏完毕,现在去微任务列表查看是否有微任务,发现 .then 的回调,执⾏它,打印 'then'

当⼀次宏任务执⾏完,再去执⾏新的宏任务,这⾥就剩⼀个定时器的宏任务了,执⾏它,打印 2

那么下面来说一下async以及await

async 就是⽤来声明⼀ 个异步⽅法,⽽ await 是⽤来等待异步⽅法执⾏

async用法:

function f() {
 return Promise.resolve('TEST');
}
// asyncF is equivalent to f!
async function asyncF() {
 return 'TEST';
}

await用法: await 命令后⾯是⼀个 Promise 对象,返回该对象的结果。如果不是 Promise 对 象,就直接返回对应的值

async function f(){
 // 等同于
 // return 123
 return await 123
}
f().then(v => console.log(v)) // 123

不管 await 后⾯跟着的是什么, await 都会阻塞后⾯的代码

async function fn1 (){
 console.log(1)
 await fn2()
 console.log(2) // 阻塞
}
async function fn2 (){
 console.log('fn2')
}
fn1()
console.log(3)

上⾯的例⼦中, await 会同步代码执⾏完,再回到 async 函数中,再执⾏之前阻塞的代码阻塞下⾯的代码(即加⼊微任务队列),先执⾏ async 外⾯的同步代码,

所以上述输出结果为: 1 , fn2 , 3 , 2

那么我们来上一个比较难的挑战吧:

async function async1() {
 console.log('async1 start')
 await async2()
 console.log('async1 end')
}
async function async2() {
 console.log('async2')
}
console.log('script start')
setTimeout(function () {
 console.log('settimeout')
})
async1()
new Promise(function (resolve) {
 console.log('promise1')
 resolve()
}).then(function () {
 console.log('promise2')
})
console.log('script end')
分析:
1. 执⾏整段代码,遇到 console.log('script start') 直接打印结果,输出 script start
2. 遇到定时器了,它是宏任务,先放着不执⾏
3. 遇到 async1() ,执⾏ async1 函数,先打印 async1 start ,下⾯遇到 await 怎么办? 先执⾏ async2 ,打印 async2 ,然后阻塞下⾯代码(即加⼊微任务列表),跳出去执⾏同步代码
4. 跳到 new Promise 这⾥,直接执⾏,打印 promise1 ,下⾯遇到 .then() ,它是微任务, 放到微任务列表等待执行
5. 最后⼀⾏直接打印 script end ,现在同步代码执⾏完了,开始执⾏微任务,即 await 下⾯的 代码,打印 async1 end
6.继续执⾏下⼀个微任务,即执⾏ then 的回调,打印 promise2
7. 上⼀个宏任务所有事都做完了,开始下⼀个宏任务,就是定时器,打印 settimeout
所以最后的结果是: scrit start 、 async1 start 、 async2 、 promise1 、 script end 、 async1 end 、 promise2 、 settimeout


相关文章
|
9月前
|
安全
员工总在找领导签字?点晴移动OA实现全员"零跑腿"办公
“张总,这份合同需要您签字!” “王经理,报销单麻烦批一下!” “李总监,请假申请您还没批,我这边着急……” 这样的场景是否每天都在你的企业上演?员工疲于跑腿找领导签字,管理层被琐碎审批缠身,业务流程卡在“最后一公里”。传统纸质审批不仅效率低下,还可能导致文件丢失、流程延误,甚至影响业务推进。 如何破解这一管理困局?点晴移动OA系统,通过智能化、无纸化、移动化办公,让审批流程“跑”起来,真正实现**全员“零跑腿”办公!
313 1
|
9月前
|
测试技术
Fast网络速度测试工具
Fast是由Netflix提供的网络速度测试工具,可快速测量用户的下载、上传速度及延迟。其全球可用、无广告干扰,并支持多种设备。测试自动进行,结果以Mbps显示。此外,用户可通过“Show more info”查看上传速度和延迟(含缓冲膨胀)。Fast以其简单快捷的特点,帮助用户了解网络性能并解决潜在问题,是评估网速的理想选择。
857 0
Fast网络速度测试工具
|
12月前
|
UED
【HarmonyOS——ArkTS语言】计算器的实现【合集】
【ArkTS语言-HarmonyOS】计算器的实现【合集】组件,点击等号后计算函数高效解析表达式并给出准确结果,达成核心功能要求。错误提示不够详尽,难以助力用户快速定位输入错误;响应式设计不足,在不同屏幕规格下适配性差。总体而言,本次实验已成功构建起基本功能框架,后续将针对上述问题深入探究优化方案,不断打磨细节,在完善计算器功能与提升用户体验的道路上持续精进,进而提升自身编程与应用开发的综合能力水平。利用按钮组件顺利完成布局设计,数字、运算符及功能按钮排列有序,操作逻辑清晰直观。
635 2
|
9月前
|
存储 算法 数据可视化
【二叉树遍历入门:从中序遍历到层序与右视图】【LeetCode 热题100】94:二叉树的中序遍历、102:二叉树的层序遍历、199:二叉树的右视图(详细解析)(Go语言版)
本文详细解析了二叉树的三种经典遍历方式:中序遍历(94题)、层序遍历(102题)和右视图(199题)。通过递归与迭代实现中序遍历,深入理解深度优先搜索(DFS);借助队列完成层序遍历和右视图,掌握广度优先搜索(BFS)。文章对比DFS与BFS的思维方式,总结不同遍历的应用场景,为后续构造树结构奠定基础。
440 10
|
9月前
|
人工智能 小程序 API
【一步步开发AI运动APP】四、使用相机组件抽帧
本文介绍了如何使用`ai-camera`组件开发AI运动APP,助力开发者深耕AI运动领域。`ai-camera`是专为AI运动场景设计的相机组件,支持多平台,提供更强的抽帧处理能力和API。文章详细讲解了获取相机上下文、执行抽帧操作以及将帧保存到相册的功能实现,并附有代码示例。无论是AI运动APP还是其他场景,该组件都能满足预览、拍照、抽帧等需求。下篇将聚焦人体识别检测,敬请期待!
|
10月前
|
存储 定位技术 数据处理
隐私失窃背后的设备“告密者”:可穿戴设备的隐私保护之道
隐私失窃背后的设备“告密者”:可穿戴设备的隐私保护之道
344 11
|
11月前
|
人工智能 自然语言处理 计算机视觉
12%计算量就能媲美原模型,Adobe、罗切斯特大学等提出YOPO剪枝技术
在人工智能领域,多模态大型语言模型(MLLMs)因卓越的视觉理解能力备受关注。然而,随着视觉标记数量增加,计算量二次扩展导致效率瓶颈。Adobe和罗切斯特大学研究人员在LLaVA中研究了视觉计算冗余,提出邻域感知注意力、不活跃头修剪及选择性层丢弃等策略,减少88%计算需求,保持性能。该研究为MLLMs处理大规模视觉数据提供新思路,显著提升实际应用中的可行性和可扩展性。论文链接:https://arxiv.org/abs/2410.06169
164 2
|
关系型数据库 分布式数据库 数据库
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)等你来战!
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)等你来战!
799 15
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)等你来战!
|
Oracle 关系型数据库 新能源
Flink CDC 在新能源制造业的实践
本文撰写自某新能源企业的研发工程师 单葛尧 老师。本文详细介绍该新能源企业的大数据平台中 CDC 技术架构选型和 Flink CDC 的最佳实践。
738 13
Flink CDC 在新能源制造业的实践
|
机器学习/深度学习 人工智能 自然语言处理
人工智能的发展现状如何?
【10月更文挑战第16天】人工智能的发展现状如何?