zl程序教程

您现在的位置是:首页 >  后端

当前栏目

js event loop事件队列详解(浏览器中)

JS浏览器 详解 Event loop
2023-09-27 14:25:56 时间
目录


前言

js是单线程的

认识一个栈两个队列

执行过程

异步任务怎么分配

简单例子

难一点的例子


前言


以下内容是js在浏览器中的事件队列执行 与在nodejs中有所区别 请注意。


js是单线程的


要知道js是单线程的 就是一件一件做 做完一件做下一件。


认识一个栈两个队列


一个调用栈Stack。

一个宏队列 macrotask 也叫tasks。

一个微队列 microtask 也叫jobs。


执行过程


js就是执行全局Script同步代码 这中间碰到一些异步任务先加进对应的队列。


做完之后 调用栈就为空了。


然后将队列(先微队列后宏队列)里面的首个任务提到调用栈来做 一件一件做完直到队列中的任务都做完。


总结就是 先做同步的任务 再做微队列的任务 再做宏队列的任务。


异步任务怎么分配


这些异步任务包括但不限于


以下分配给宏队列


setTimeout

setInterval

requestAnimationFrame

I/O

UI rendering

以下分配给微队列


Promise

Object.observe

MutationObserver

常见的宏队列 setTimeout 常见的微队列 Promise。


简单例子
 console.log( 同步任务1 

 setTimeout(() {

 console.log( 宏任务 

 new Promise((resolve, reject) {

 console.log( 同步任务2 

 resolve( 微任务 

 }).then((data) {

 console.log(data);

 console.log( 同步任务3 

结果是 按标号加任务 按箭头执行 :

image.png

image.png

需要注意的是Promise的第一层没有执行回调之前是同步的 也就是上面的同步任务2。

难一点的例子
 console.log( 同步任务1 

 console.log( 同步任务2 

 new Promise((resolve, reject) {

 console.log( 同步任务3 

 setTimeout(() {

 console.log( 宏任务1 

 Promise.resolve()

 .then(() {

 console.log( 微任务5 

 .then(() {

 console.log( 微任务6 

 resolve( 微任务1 

 .then((data) {

 console.log(data);

 return 微任务3 

 .then((data) {

 console.log(data);

 setTimeout(() {

 console.log( 宏任务2 

 }, 0);

 new Promise((resolve, reject) {

 resolve( 微任务2 

 .then((data, resolve) {

 console.log(data);

 return 微任务4 

 .then((data) {

 console.log(data);

 console.log( 同步任务4 

如何看呢 先看第一层 红色代表同步 绿色微任务 蓝色宏任务。

我们会把同步任务执行完 然后看见微任务有俩 宏任务也有俩。

本来的执行顺序可能是这样 我这里按照序号来表达顺序了 请和简单例子区分开来

image.png

但是没那么顺利 执行到标号6时不一样了。


因为微任务执行过程中可能会产生新的微任务。


上面的微任务1执行完会把微任务3加在微任务2后面 也就是微任务2执行完也轮不到宏任务 会继续执行新的微任务直到微任务队列暂时为空。


所以接下来会按照加入队列的顺序执行完四个微任务 这时候发现没有新的微任务产生 才开始执行宏任务

image.png

但是需要注意的是 上面执行到标号5时又不一样了 宏任务一执行后又产生了新的微任务 所以宏任务两个并没有顺利连续执行 而是被插入的微任务拦住了。

要记住微任务与宏任务队列都存在时一定是微任务先执行完再来执行宏任务 即使是宏任务执行产生的微任务也同理

image.png

所以最后的答案 如果存在不理解的 可以在认真回顾一下上文

image.png