面试官:说说你对事件循环的理解

一、事件循环是什么

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

JavaScript中,所有的任务都可以分为

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

  • 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等

同步任务与异步任务的运行流程图如下:

从上面我们可以看到,同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环

二、宏任务与微任务

如果将任务划分为同步任务和异步任务并不是那么的准确,举个例子:

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 毫秒后console.log(2)回调推入 Event Queue 中
  • new Promise ,同步任务,主线程直接执行
  • .then ,异步任务,放到 Event Table
  • console.log(3),同步任务,主线程执行

所以按照分析,它的结果应该是 1 => 'new Promise' => 3 => 2 => 'then'

但是实际结果是:1=>'new Promise'=> 3 => 'then' => 2

出现分歧的原因在于异步任务执行顺序,事件队列其实是一个“先进先出”的数据结构,排在前面的事件会优先被主线程读取

例子中 setTimeout回调事件是先进入队列中的,按理说应该先于 .then 中的执行,但是结果却偏偏相反

原因在于异步任务还可以细分为微任务与宏任务

微任务

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

常见的微任务有:

  • Promise.then

  • MutaionObserver

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

  • process.nextTick(Node.js)

宏任务

宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合

常见的宏任务有:

  • script (可以理解为外层同步代码)
  • setTimeout/setInterval
  • UI rendering/UI事件
  • postMessage、MessageChannel
  • setImmediate、I/O(Node.js)

这时候,事件循环,宏任务,微任务的关系如图所示

按照这个流程,它的执行机制是:

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

回到上面的题目

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) ,直接打印 1
// 遇到定时器,属于新的宏任务,留着后面执行
// 遇到 new Promise,这个是直接执行的,打印 'new Promise'
// .then 属于微任务,放入微任务队列,后面再执行
// 遇到 console.log(3) 直接打印 3
// 好了本轮宏任务执行完毕,现在去微任务列表查看是否有微任务,发现 .then 的回调,执行它,打印 'then'
// 当一次宏任务执行完,再去执行新的宏任务,这里就剩一个定时器的宏任务了,执行它,打印 2

三、async与await

async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是用来声明一个异步方法,而 await是用来等待异步方法执行

async

async函数返回一个promise对象,下面两种方法是等效的

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

await

正常情况下,await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值

async function f(){// 等同于// return 123return 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 函数中,再执行之前阻塞的代码

所以上述输出结果为:1fn232

四、流程分析

通过对上面的了解,我们对JavaScript对各种场景的执行顺序有了大致的了解

这里直接上代码:

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

所以最后的结果是:script startasync1 startasync2promise1script endasync1 endpromise2settimeout

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/737780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

一、面试官心理分析 其实这是很常见的一个问题,这俩问题基本可以连起来问。既然是消费消息,那肯定要考会不会重复消费?能不能避免重复消费?或者重复消费了也别造成系统异常可以吗?这个是 MQ领域的基本问题,…

还不知道快速原型设计?别担心,我们来解释给你听!

从一个想法到产品的实施是一个混乱的过程,毫无疑问,我们需要努力建立这个想法。但“光明”的想法是好是坏呢?幸运的是,我们有一个工具可以做到这一点——原型。原型是最终产品的模拟或样本版本,可用于发布前与用户反复…

部署私有KMS服务器,并设置自动激活Windows和office

介绍 vlmcsd是一个KMS激活服务器的模拟器,可以在Windows Server之外的平台上部署自己的KMS服务器。它是一个开源项目,由Wind4开发,目前在Linux上运行(包括Android、FreeBSD、Solaris、Minix、Mac OS、iOS和Windows等)…

【pycharm使用ssh连接服务器】

2、pycharm使用ssh连接服务器 1、具体流程2、一些需要注意的小问题2.1 更改代码地址2.2 本地代码上传到服务器2.3 在服务器的环境中上新安装库,但是pycharm检测不到 1、具体流程 打开pycharm – File – Setting 输入服务器的IP地址,端口号、登录账号名…

Linux中三次握手,四次挥手状态图,端口复用 半关闭状态,心跳包

tcp三次握手和四次挥手状态图: 为什么需要2MSL: 原因1:让四次挥手过程更加可靠,确保最后一个发送给对方的ACK到达;若对方没有收到ACK应答,对方会再次发送FIN请求关闭,此时在2MSL时间内被动关闭…

盛元广通粮油质量检测实验室管理系统

近年来对于食品安全问题层出不穷,为提高粮食检测中心管理水平,关系到千千万万的消费者的健康饮食问题,粮油作为老百姓日常生活饮食必需品、消耗品,需从源头上对粮食在本省(区、市、县)不同粮食品种检测检测…

Intel@cpu产品参数和命名@单核睿频和全核睿频

文章目录 选择合适的cpuintel cpu型号和命名小结 cpu排行时钟速度睿频单核睿频和全核睿频网络上流传的方法 在线查询 产品比较跑分比较 选择合适的cpu 如何选择游戏 CPU - 英特尔 (intel.cn)在决定购买具体的产品之前,建议广泛地查阅用户对它的评价以及是否有哪些因素是不满足…

7个学习自动化测试小技巧希望能帮助到你

一、编程语言 当我开始担任手动测试人员时,我不喜欢编码。但是,当我逐渐进入自动化领域时,对我来说很清楚,如果没有对编程语言的一些基本了解,就无法编写逻辑自动化测试脚本。 对编程有一点了解,不仅可以…

网络安全防御保护 Day7

1.因为FW1和FW2已处于双机热备状态,所以只需要对主设备进行配置即可。进入FW1的配置界面,选择“网络”界面,点击“IPsec”,进行IPsec通道的基本配置,这里选择的是“电信”链路。 2.完成上述配置后,进行待加…

揭秘防爆气象仪器:超声波监测原理如何守护安全?

TH-WFB5随着科技的不断进步,防爆气象仪器已成为现代工业生产中不可或缺的重要设备。这些仪器采用先进的超声波监测原理,能够实时、准确地监测环境中的各种气象参数,为企业的安全生产提供有力保障。 一、超声波监测原理简介 超声波是指频率高于…

从焦虑到成功:一个软件测试工程师的逆袭之路

日常大家聊天时经常提及一个关键词——大环境不好,由此带来了很多行为的变化,有的人迷茫,有的人躺平。本文给大家介绍发生在我身上和身边的真实案例,希望能带给你一些输入。 案例一:曾经的我也极度焦虑 我是2008年参加…

BUU [网鼎杯 2020 半决赛]AliceWebsite

BUU [网鼎杯 2020 半决赛]AliceWebsite 开题&#xff1a; hint附件是源码。在index.php中有一个毫无过滤的本地文件包含 <?php $action (isset($_GET[action]) ? $_GET[action] : home.php); if (file_exists($action)) {include $action; } else {echo "File not…

Unity接入海量RTSP直播流,多线程渲染

Unity 播放海量RTSP视频&#xff0c;多线程播放&#xff0c;长时间运行稳定 Unity 播放海量RTSP视频&#xff0c;多线程渲染 使用的libvlc库&#xff0c;目前支持windows、Linux平台 25路视频同时播放&#xff0c;测试持续运行1晚上&#xff0c;运行稳定&#xff0c;不掉帧&am…

安卓studio安装(从安装到配置到helloworld)

安卓studio安装 2024.3.11官网的版本&#xff08;有些翻墙步骤下载东西也解决了&#xff09; 这次写的略有草率&#xff0c;后面会更新布局的&#xff0c;因为截图量太大了&#xff0c;有需要的小伙伴可以试着接受一下哈哈哈哈 !(https://gitee.com/jiuzheyangbawjf/img/raw/ma…

二叉搜索树题目:前序遍历构造二叉搜索树

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 解法三思路和算法代码复杂度分析 解法四思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;前序遍历构造二叉搜索树 出处&#xff1a;1008. …

【解决】Sublime Text找不到Package Control选项,且输入install也不显示Install Package(其中一种情况)

【问题描述】 Sublime Text 找不到 Package Control 选项&#xff0c;且输入 install 也不显示 Install Package 【解决方法】&#xff08;其中一种情况&#xff09; 1、工具栏 Preferences -> Settings&#xff0c;点开查看设置文档 2、检查 "ignored_packages&q…

提示并输入一个字符串,统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C++风格字符串完成

#include <iostream> #include <array> using namespace std;int main() {cout<<"请输入一个字符串"<<endl;//array<string,100> str;string str;getline(cin,str);int daxie0,xiaoxie0,num0,space0,other0;int lenstr.size();;for(in…

使用sunny-Ngrok免费实现内网穿透

1、注册用户 网址&#xff1a;https://ngrok.cc/login/register 2、实名认证 注册成功之后&#xff0c;登录系统&#xff0c;进行实名认证&#xff0c;认证费两元。认证通过后才能开通隧道。 3、开通隧道 选择免费的隧道 4、开通成功后查看开通隧道 5、启动隧道 下载…

日常002:双系统时间不一致问题

日常002&#xff1a;双系统时间不一致问题 推荐解决方法&#xff1a;Windows管理员执行如下命令&#xff0c;将硬件时钟设置为UTC时间 reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /d 1 /t REG_DWO…

计算机网络—以太网接口和链路配置

目录 1.拓扑图 2.以太网交换机基础配置 3.配置手动模式的链路聚合 4.配置静态 LACP 模式的链路聚合 5.配置文件 1.拓扑图 2.以太网交换机基础配置 华为交换机接口默认开启了自协商功能&#xff0c;需要手动配置S1与 S2上G0/0/9和G0/0/10接口的速率。 首先修改交换机的设…