当前位置: 首页 > Web前端 > JavaScript

浏览器中的js事件循环(Eventloop)

时间:2023-03-27 18:04:29 JavaScript

原文地址:https://qianduan.shop/blogs/d...本文将简单介绍一下浏览器中的js事件循环机制,帮助我们理解浏览器环境js代码是如何运行的。Javascript的一大特点是单线程,这意味着它一次只能做一件事。事件循环(EventLoop)的诞生就是为了协调事件、用户交互、UI渲染、网络处理等行为,防止线程阻塞。浏览器事件循环1、宏任务(MacroTask)和微任务(MicroTask)浏览器中js事件循环的异步队列有两种:宏(宏任务)队列和微(微任务)队列。可以有多个宏任务队列,只有一个微任务队列。常见宏任务:定时器(setTimeout、setInterval)、脚本(整体代码)、I/O操作、UI渲染等常见微任务:Promise.then(Promise的回调方法)、MutationObserver(html5新特性)等.2.事件循环过程分析一个完整的事件循环过程可以概括为以下几个阶段:【外链图片传输失败,源站可能有防盗链机制,建议保存图片再上传直接(img-NmXzcMT0-1637111445594)(/static/images/event_loop.png)]①一开始执行栈是空的,我们可以把执行栈看成是一个存放函数调用的栈结构,遵循先入先出的原则,最后出来。microtask队列为空,macrotask队列中只有一个script脚本(整体代码)。②将全局上下文(script标签)压入执行栈,同步代码执行。在执行过程中会判断是同步任务还是异步任务。通过调用一些接口,可以生成新的宏任务和微任务,并推入各自的任务队列。同步代码执行完毕后,脚本脚本将从宏任务队列中移除。这个过程本质上就是队列中的宏任务执行和出队的过程。③上一步我们出队的是宏任务,这一步我们处理的是微任务。但需要注意的是,每执行一次宏任务,都会检查微任务队列中是否有待处理的微任务。如果有,则依次执行,清空队列;如果没有,将执行下一个宏任务。④执行渲染操作,更新界面⑤检查是否有webworkertask,如果有则处理有microtask队列。如果有,则先执行微任务队列中的所有任务,如果没有,则读取宏任务队列中的最前面的任务。macrotask在执行过程中,如果遇到microtask,会依次加入到microtask队列中。栈为空后,再次读取微任务队列中的任务,以此类推。例如:Promise.resolve().then(()=>{console.log('Promise1');setTimeout(()=>{console.log('setTimeout1');},0);});setTimeout(()=>{console.log('setTimeout2');Promise.resolve().then(()=>{console.log('Promise2');})},0);输出结果:Promise1,setTimeout2,promise2,setTimeout1实例分析:①全局同步代码(整个代码块)执行完毕(这是一个宏任务),执行完成(上面代码生成一个宏tasksetTimeout2andamicrotaskPromise1),检查并执行microtask队列,输出Promise1,同时生成一个macrotasksetTimeout1。②然后查看宏任务队列,宏任务setTimeout2先于setTimeout1执行宏任务setTimeout2,输出setTimeout2。③当宏任务setTimeout2执行时,会产生微任务Promise2,放入微任务队列,然后先清除微任务队列中的所有任务,输出Promise2。④清除完microtask队列中的所有任务后,会去macrotask队列中再取一个,此时执行setTimeout1。