位置: IT常识 - 正文

带你深入理解js事件循环机制(深入理解ts)

编辑:rootadmin
带你深入理解js事件循环机制 同步任务和异步任务(微任务和宏任务)

推荐整理分享带你深入理解js事件循环机制(深入理解ts),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:深入理解rcu,什么是深入理解,带你深入理解计算机pdf,深入理解llvm,深入理解osgi,带你深入理解计算机pdf,带你深入理解计算机pdf,深入理解osgi,内容如对您有帮助,希望把文章链接给更多的朋友!

JavaScript是一门单线程语言

分为同步任务和异步任务

同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务。

异步任务指的是,不进入主线程、而进入"任务队列"的任务;只有等主线程任务全部执行完毕,"任务队列"的任务才会进入主线程执行。

异步任务分为宏任务和微任务

new promise()、console.log()属于同步任务

宏任务(macrotask)微任务(microtask)谁发起的宿主(Node、浏览器)JS引擎具体事件1. script (可以理解为外层同步代码) 2. setTimeout/setInterval 3. UI rendering/UI事件 4. postMessage,MessageChannel 5. setImmediate,I/O(Node.js)1. Promise 2. MutaionObserver 3. Object.observe(已废弃;Proxy 对象替代) 4. process.nextTick(Node.js)谁先运行后运行先运行会触发新一轮Tick吗会不会

执行过程: 同步任务 —> 微任务 —> 宏任务

1.先执行所有同步任务,碰到异步任务放到任务队列中 2.同步任务执行完毕,开始执行当前所有的异步任务 3.先执行任务队列里面所有的微任务 4.然后执行一个宏任务 5.然后再执行所有的微任务 6.再执行一个宏任务,再执行所有的微任务·······依次类推到执行结束。

3-6的这个循环称为事件循环Event Loop

事件循环是JavaScript实现异步的一种方法,也是JavaScript的执行机制

async/await (重点)(个人注解:async/await 底层依然是 Promise,所以是微任务,只是 await 比较特殊)

async

当我们在函数前使用async的时候,使得该函数返回的是一个Promise对象

async function test() {return 1 // async的函数会在这里帮我们隐士使用Promise.resolve(1)}// 等价于下面的代码function test() { return new Promise(function(resolve, reject) { resolve(1) })}// 可见async只是一个语法糖,只是帮助我们返回一个Promise而已

await

await表示等待,是右侧「表达式」的结果,这个表达式的计算结果可以是 Promise 对象的值或者一个函数的值(换句话说,就是没有特殊限定)。并且只能在带有async的内部使用

使用await时,会从右往左执行,当遇到await时, ★★★★★会阻塞函数内部处于它后面的代码,去执行该函数外部的同步代码,当外部同步代码执行完毕,再回到该函数内部执行剩余的代码★★★★★, 并且当await执行完毕之后,会先处理微任务队列的代码

示例//1console.log('1');//2setTimeout(function() {console.log('2');process.nextTick(function() {console.log('3');})new Promise(function(resolve) {console.log('4');resolve();}).then(function() {console.log('5')})})//3process.nextTick(function() {console.log('6');})//4new Promise(function(resolve) {console.log('7');resolve();}).then(function() {console.log('8')})//5setTimeout(function() {console.log('9');process.nextTick(function() {console.log('10');})new Promise(function(resolve) {console.log('11');resolve();}).then(function() {console.log('12')})})// 先执行1 输出1// 执行到2,把setTimeout放入异步的任务队列中(宏任务)// 执行到3,把process.nextTick放入异步任务队列中(微任务)// 执行到4,上面提到promise里面是同步任务,所以输出7,再将then放入异步任务队列中(微任务)// 执行到5,同2// 上面的同步任务全部完成,开始进行异步任务// 先执行微任务,发现里面有两个微任务,分别是3,4压入的,所以输出6 8// 再执行一个宏任务,也就是第一个setTimeout// 先输出2,把process.nextTick放入微任务中,再如上promise先输出4,再将then放入微任务中// 再执行所以微任务输出输出3 5// 同样的,再执行一个宏任务setTImeout2,输出9 11 在执行微任务输出10 12// 所以最好的顺序为:1 7 6 8 2 4 3 5 9 11 10 12 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' )}, 0 )async1();new Promise( function ( resolve ) {console.log( 'promise1' )resolve();} ).then( function () {console.log( 'promise2' )} )console.log( 'script end' )// 首先执行同步代码,console.log( 'script start' )// 遇到setTimeout,会被推入宏任务队列// 执行async1(), 它也是同步的,只是返回值是Promise,在内部首先执行console.log( 'async1 start' )// 然后执行async2(), 然后会打印console.log( 'async2' )// 从右到左会执行, 当遇到await的时候,阻塞后面的代码,去外部执行同步代码// 进入new Promise,打印console.log( 'promise1' )// 将.then放入事件循环的微任务队列// 继续执行,打印console.log( 'script end' )// 外部同步代码执行完毕,接着回到async1()内部, 继续执行 await async2() 后面的代码,执行 console.log( 'async1 end' ) ,所以打印出 async1 end 。(个人理解:async/await本质上也是Promise,也是属于微任务的,所以当遇到await的时候,await后面的代码被阻塞了,应该也是被放到微任务队列了,当同步代码执行完毕之后,然后去执行微任务队列的代码,执行微任务队列的代码的时候,也是按照被压入微任务队列的顺序执行的)// 执行微任务队列的代码, 打印 console.log( 'promise2' )// 进入第二次事件循环,执行宏任务队列, 打印console.log( 'setTimeout' )/** * 执行结果为: * script start * async1 start * async2 * promise1 * script end * async1 end * promise2 * setTimeout */ console.log(1);async function fn(){console.log(2)new Promise((resolve)=>{resolve();}).then(()=>{console.log("XXX")})await console.log(3)console.log(4)}fn();new Promise((resolve)=>{console.log(6)resolve();}).then(()=>{console.log(7)})console.log(8)// 执行结果为:1 2 3 6 8 XXX 4 7/*前面的 1 2 3 6 8 不再解析,重点是后面的 XXX 4 7,由此可见 await console.log(3) 之后的代码 console.log(4) 是被放入到微任务队列了,代码 console.log("XXX") 也是被压入微任务队列了,console.log("XXX")是在 console.log(4) 之前,所以当同步任务执行完毕之后,执行微任务队列代码的时候,优先打印出来的是 XXX ,然后才是 4 。*/ console.log(1);async function fn(){console.log(2)await console.log(3)await console.log(4)await console.log("await之后的:",11)await console.log("await之后的:",22)await console.log("await之后的:",33)await console.log("await之后的:",44)}setTimeout(()=>{console.log(5)},0)fn();new Promise((resolve)=>{console.log(6)resolve();}).then(()=>{console.log(7)})console.log(8)/** * 执行结果为: * 1 * 2 * 3 * 6 * 8 * 4 * 7 * await之后的: 11 * await之后的: 22 * await之后的: 33 * await之后的: 44 * 5 *//*由此可见,代码执行的时候,只要碰见 await ,都会执行完当前的 await 之后,把 await 后面的代码放到微任务队列里面。但是定时器里面的 5 是最后打印出来的,可见当不断碰见 await ,把 await 之后的代码不断的放到微任务队列里面的时候,代码执行顺序是会把微任务队列执行完毕,才会去执行宏任务队列里面的代码。*/ Promise.resolve().then(() => {console.log(0);return Promise.resolve(4) // 顺延2位如果是return 4 则打印 0、1、4、2、3、5、6、7}).then(res => console.log(res))Promise.resolve().then(() => {console.log(1);}).then(() => {console.log(2);}).then(() => {console.log(3);}).then(() => {console.log(5);}).then(() => {console.log(6);}).then(() => {console.log(7);})/*此题主要注意的是原生的Promise的then方法中,如果返回的是一个普通值,则返回的值会被立即调用并赋值给resolve函数,如果返回的是一个thenable,则then方法将会被放入到微队列中执行,如果返回的是一个Promise.resolve,则会再加一次微任务队列。即微任务后移,Promise.resolve本身是执行then方法,而then方法本身是在微任务队列中执行,同时return Promise.resolve时是将resolve调用的返回值 作为上级then中resolve的参数传递,调用外层then方法时本身是在微队列里面,所以函数的执行顺序是要在微队列中下移两次。*/ 根据w3c的最新解释每个任务都有一个任务类型 , 同一个类型的任务必须在一个队列也就是一共有多个队列 , 不同类型的任务可以分属不同的队列,在一个次事件循环中,浏览器可以根据实际情况从不同的队列中区出任务执行浏览器必须准备好一个微队列 , 微队列中的任务优先所有其他任务执行他里面的东西 所有都要给我等 连绘制任务 都要等 就是最高优先级了带你深入理解js事件循环机制(深入理解ts)

随着浏览器的复杂度急剧提升 W3C不再使用宏队列的说法

在目前chrome的实现中 至少包含了下面的队列

延时队列 : 用于存放计时器到达后的回调任务 , 优先级中交互列队 : 用于存放用户操作后产生的事件处理任务 , 优先级高微队列 : 用户存放需要最快执行的任务 优先级最高

添加任务到微队列的主要方式主要是使用 Promise、MutationObserver

例如:// 立即把一个函数添加到微队列Promise.resolve().then(函数)

任务有优先级吗?

任务没有优先级,在消息队列中先进先出但消息队列是有优先级的// 立刻把一个函数添加到微队列 最高执行promise.resolve().then(函数)setTimeOut(()=>{ // 第三步执行延时队列中的任务console.log(1);},0)promise.resolve().then(()=>{ // 第二步执行微队列中的任务console.log(2);})console.log(3); // 第一步先执行全局js// 3 2 1 面试题1、如何理解 JS 的异步?

JS是一门单线程的语言,这是因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。

而渲染主线程承担着诸多的工作,渲染页面、执行 JS 都在其中运行。

如果使用同步的方式,就极有可能导致主线程产生阻塞,从而导致消息队列中的很多其他任务无法得到执行。这样一来,一方面会导致繁忙的主线程白白的消耗时间,另一方面导致页面无法及时更新,给用户造成卡死现象。

所以浏览器采用异步的方式来避免。具体做法是当某些任务发生时,比如计时器、网络、事件监听,主线程将任务交给其他线程去处理,自身立即结束任务的执行,转而执行后续代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的末尾排队,等待主线程调度执行。

在这种异步模式下,浏览器永不阻塞,从而最大限度的保证了单线程的流畅运行。

2、 阐述一下js的事件循环

事件循环又叫做消息循环,是浏览器渲染主线程的工作方式。

在 Chrome 的源码中,它开启一个不会结束的 for 循环,每次循环从消息队列中取出第一个任务执行,而其他线程只需要在合适的时候将任务加入到队列末尾即可。

过去把消息队列简单分为宏队列和微队列,这种说法目前已无法满足复杂的浏览器环境,取而代之的是一种更加灵活多变的处理方式。

根据 W3C 官方的解释,每个任务有不同的类型,同类型的任务必须在同一个队列,不同的任务可以属于不同的队列。不同任务队列有不同的优先级,在一次事件循环中,由浏览器自行决定取哪一个队列的任务。但浏览器必须有一个微队列,微队列的任务一定具有最高的优先级,必须优先调度执行。

3、JS 中的计时器能做到精确计时吗?为什么?

不行,因为:

1.计算机硬件没有原子钟,无法做到精确计时 2.操作系统的计时函数本身就有少量偏差,由于 JS 的计时器最终调用的是操作系统的函数,也就携带了这些偏差 3.按照 W3C 的标准,浏览器实现计时器时,如果嵌套层级超过 5 层,则会带有 4 毫秒的最少时间,这样在计时时间少于 4 毫秒时又带来了偏差 4.受事件循环的影响,计时器的回调函数只能在主线程空闲时运行,因此又带来了偏差

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。 有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:

文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文链接地址:https://www.jiuchutong.com/zhishi/298587.html 转载请保留说明!

上一篇:强化学习之stable_baseline3详细说明和各项功能的使用

下一篇:【TFS-CLUB社区 第4期赠书活动】〖Flask Web全栈开发实战〗等你来拿,参与评论,即可有机获得(tf fans club)

  • iphone13怎么显示电量(iphone13怎么显示卡上的电话号码)

    iphone13怎么显示电量(iphone13怎么显示卡上的电话号码)

  • 苹果怎么识别图片二维码(苹果怎么识别图片物品)

    苹果怎么识别图片二维码(苹果怎么识别图片物品)

  • 手机国行和其他版本有什么区别(手机国行和其他版本怎么查看)

    手机国行和其他版本有什么区别(手机国行和其他版本怎么查看)

  • 蓝牙音响aux啥意思(蓝牙音箱aux模式是什么意思)

    蓝牙音响aux啥意思(蓝牙音箱aux模式是什么意思)

  • 华为只换外屏影响大吗(华为换外屏影响截图吗)

    华为只换外屏影响大吗(华为换外屏影响截图吗)

  • 联通手机卡欠费多久自动销号(联通手机卡欠费停机会影响征信吗)

    联通手机卡欠费多久自动销号(联通手机卡欠费停机会影响征信吗)

  • 配电室直流屏的作用(配电室直流屏的作用,故障报警如何排除)

    配电室直流屏的作用(配电室直流屏的作用,故障报警如何排除)

  • xr刷新率(苹果刷新率在哪里设置)

    xr刷新率(苹果刷新率在哪里设置)

  • 荣耀30pro什么时候上市(荣耀30pro什么时候降价吗)

    荣耀30pro什么时候上市(荣耀30pro什么时候降价吗)

  • 抖音有没有一键取消喜欢选项(抖音有没有一键取消喜欢)

    抖音有没有一键取消喜欢选项(抖音有没有一键取消喜欢)

  • mate30pro超广角怎么开(mate30 pro广角)

    mate30pro超广角怎么开(mate30 pro广角)

  • 红米6a储存卡放哪(红米手机内存卡)

    红米6a储存卡放哪(红米手机内存卡)

  • airpods一二代有什么区别(airpods 一二代)

    airpods一二代有什么区别(airpods 一二代)

  • 笔记本电脑i5和i7有什么区别(笔记本电脑i5和i7哪个更好)

    笔记本电脑i5和i7有什么区别(笔记本电脑i5和i7哪个更好)

  • wifi6兼容wifi5吗(wifi6不兼容wifi5)

    wifi6兼容wifi5吗(wifi6不兼容wifi5)

  • 华为mate30隔空设置为什么没有(华为mate30隔空设置更改)

    华为mate30隔空设置为什么没有(华为mate30隔空设置更改)

  • 三星note10和s10的区别(三星note10 和s10)

    三星note10和s10的区别(三星note10 和s10)

  • 蜗牛卡可以长期用吗(蜗牛卡不能用了怎么办?)

    蜗牛卡可以长期用吗(蜗牛卡不能用了怎么办?)

  • 滴滴怎么抢单更快(滴滴出行如何抢单)

    滴滴怎么抢单更快(滴滴出行如何抢单)

  • 苹果恢复大师可以恢复多久的信息(苹果恢复大师可以恢复照片吗)

    苹果恢复大师可以恢复多久的信息(苹果恢复大师可以恢复照片吗)

  • xr有指纹吗(苹果xr有指纹吗)

    xr有指纹吗(苹果xr有指纹吗)

  • 三维触控按不出来(三维触控按不出怎么办)

    三维触控按不出来(三维触控按不出怎么办)

  • Win11电脑屏幕倒过来了怎么办?Win11屏幕倒过来的解决方法(win11电脑屏幕倒过来了怎么办)

    Win11电脑屏幕倒过来了怎么办?Win11屏幕倒过来的解决方法(win11电脑屏幕倒过来了怎么办)

  • 2022最新完美破解微擎小程序前端后端模块牛牛盲盒、牛牛盲盒小程序、盲盒小程序-OK源码中国破解(完美破费是什么意思)

    2022最新完美破解微擎小程序前端后端模块牛牛盲盒、牛牛盲盒小程序、盲盒小程序-OK源码中国破解(完美破费是什么意思)

  • Python元类的使用(python元数据)

    Python元类的使用(python元数据)

  • 息税前利润和销售利润
  • 简易征收预缴税率怎么算
  • 平均税额怎么算
  • 销售货物应税劳务服务清单给客户一份是不是就可以了
  • 福利费需要申报吗
  • 个税系统如何增员
  • 个税身份验证不通过
  • 待清算商户款项怎么做账
  • 小规模纳税人季报还是月报?
  • 其他应付款转为营业外收入要交税吗
  • 向投资者分配现金股利会影响负债吗
  • 新会计准则开办费分摊
  • 增值税一般纳税人税率是多少?
  • 个体开建筑服务税率多少?
  • 买一赠一销售收入计算案例
  • 以前年度亏损本季度盈利所得税申报
  • 社保补缴上月的在当月扣款
  • 发票显示不抵扣什么意思
  • 营改增后自产产品用于在建工程
  • 为外国公司提供境内服务
  • 增值税专用发票怎么开
  • 公司发工资了
  • 一式三联的收据哪一联要盖财务章
  • 华为手机屏幕有个圆点怎么取消
  • mac怎么转到苹果系统
  • qbupdate.exe - qbupdate是什么进程 有什么作用
  • 一台电脑两个显示器显示不一样的内容
  • 怎么登明细分类账
  • thinkphp curl
  • php编程入门教程
  • 企业销售商品怎么做分录
  • 胡山森林公园门票多少钱一张
  • php返回函数值的关键字
  • 个人博客登录入口
  • 水利建设基金按季度缴纳
  • thinkphp框架作用
  • php正则匹配时间
  • 调出command命令窗口
  • 信用减值损失在资产负债表中怎么表示
  • 专用发票费率
  • 工会经费计提的会计分录
  • 采购商品的运费计入成本吗
  • 水利基金补申报怎么操作
  • 制造费用转入什么
  • 配件盘点的方法
  • 材料已经入库但是没有发票怎么做账
  • 文化传媒有限公司英文
  • mysql_real_query
  • 实收资本与资本公积之和小于实收资本
  • 本年利润必须转入利润分配吗
  • 研发支出资本化计入什么科目
  • 公司临时工的车可以买吗
  • 应收应付账款统计表
  • 滞纳金冲留底税额怎么算
  • 政府非税收入项目挂接流程图
  • 收入的确认条件包括
  • 出差补贴应该怎么入账
  • SQL Server Alwayson创建代理作业的注意事项详解
  • mysql解压版
  • mysql 5.7.11 winx64安装配置方法图文教程
  • sql批量修改数据语句
  • Windows任务栏中的活动程序间不能切换对吗
  • 清华同方笔记本无线网络开关在哪
  • issch.exe
  • win10系统d盘变成e盘,进入winpe盘符正常
  • ubuntuiso
  • .exe是什么意思
  • win7电脑找不到无线网络连接图标
  • 微软推送win11
  • linux用户配置文件是什么
  • java面试题简书
  • linux编写一个脚本
  • android开发技术介绍
  • javascript中substr,substring,slice.splice的区别说明
  • 简单的jquery插件实例
  • ThreadPool.RegisterWaitForSingleObject 设置等待超时事件
  • 浏览器兼容性问题是什么意思
  • python操作mongodb数据库
  • 财税公司经营范围介绍
  • 税控盘红字发票开具流程
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设