js的微任务和宏任务

一、任务队列

弄清楚这个概念要先明白什么是任务:

一个任务就是指计划由标准机制来执行的任何 JavaScript,如程序的初始化、事件触发的回调等。 

除了使用事件,你还可以使用 setTimeout() 或者 setInterval() 来添加任务

所谓任务,浅显来说就是代码块开始执行的入口(确切地说,是函数栈的入口

二、异步是怎么实现的event loop循环

主线程发起如果一个异步请求,相应的工作线程就接收这个请求并进行处理,期间,主线程发完请求之后就去干别的事情去了。等到工作线程的处理有了结果,浏览器内部就分配一个线程(event table)出来,通知主线程,刚刚发起的异步请求有了结果(这个通知过程其实是将回调函数推入消息队列(event queue)中,也叫事件队列,也叫任务队列),等到主线程处理完了当前调用栈中的任务,就会从这个消息队列中读取消息,也就是调用回调。这样就完成了一次异步操作。

而javascript执行代码的机制就是不断地从判断主线程是否为空,为空就读取消息队列(event queue)的回调并执行的过程。

我的理解:执行js代码的时候会判断代码是同步还是异步,同步进入主线程执行,异步进入event table执行。异步执行完后会将其回调函数注册进入event queue(微任务和宏任务不是同一个event queue)。js会检测主线程是否还有代码执行,如果执行完就去查看event queue中是否有已经注册了的函数,如果有就执行。没有就判断主线程是否为空。为空就判断消息队列(event queue),循环往复。

 

 

 

 

盗的大佬的图

三、微任务和宏任务

宏任务(macrotask)

可以理解是每次消息队列执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到消息队列中执行)。

浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染,

进入任务栈等待主线程执行的主代码块,包括从异步队列里加入到栈的,如setTimeout()、setInterval()的回调,其中不含异步队列中的微任务如Promise.then回调。

微任务(microtask)

是异步队列中,在当前这一次宏任务执行完后,页面渲染之前要执行的任务。

此时注意,即使当前微任务执行过程中,产生了新的微任务,也会在下一个宏任务开始执行之前且当前事件循环结束之前执行完所有的微任务。

注意:

1.微任务是用于插队的

2.微任务是快于宏任务的,但是一般是由宏任务(<script>)开始执行。

注:为什么说微任务是用于插队的呢?因为每次执行宏任务之前都会看有没有微任务,不管微任务是何时加入队列的,都会清空微任务队列之后才会执行下一个宏任务

3.微任务>dom渲染>宏任务

1)main script中的代码优先执行(编写的顶层script代码);
2)在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行
3)也就是宏任务执行之前,必须保证微任务队列是空的;
4) 如果不为空,那么久优先执行微任务队列中的任务(回调)

宏任务一般是:包括整体代码script,setTimeout,setInterval。

微任务:Promise,process.nextTick。

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

<script>标签可以理解为一个宏任务,因为这是一个代码段的入口,且必须要先加载。 排前面的 script 先执行,执行其内部的【同】,再执行其【微】,接着就轮到下一个大的宏,也就是执行下一个 script,【同】、【微】。。。顺序执行完后,再从头开始,看第一个 script 是否有需要执行的【宏】,再去下一个 script 中找 【宏】,等大家宏结束后,进入下一轮循环。

1.,宏任务和微任务的执行时间

前四行代码会给网页增加一个结构和内容,可以帮我们判断渲染和宏任务、微任务的前后。

最开渲染没有出现的原因:

文档解析 和 页面渲染 是两个不同的概念

浏览器打开一个网页的过程是: 加载一部分代码 >>> 文档解析(如有js则立即执行) >>> 页面渲染 >>> 加载下一部分代码 >>> 文档解析 >>> 页面渲染 .......

文档解析 是根据html代码在系统内存中创建Dom元素,这时Dom元素只是在内存中,你在这之后可以用js访问之前已经解析了的Dom元素。但却不会立即绘制到页面上。 直到 页面渲染 时才会把内存中的Dom元素绘制到页面上。

而微任务是先于dom渲染的所以在执行promise的任务时,页面没有渲染。

 

宏任务的执行是在dom渲染后,所以页面会出现文本内容。

 

2.微任务与宏任务的区别

这个就像去银行办业务一样,先要取号进行排号。
一般上边都会印着类似:“您的号码为XX,前边还有XX人。”之类的字样。

因为柜员同时职能处理一个来办理业务的客户,这时每一个来办理业务的人就可以认为是银行柜员的一个宏任务来存在的,当柜员处理完当前客户的问题以后,选择接待下一位,广播报号,也就是下一个宏任务的开始。
所以多个宏任务合在一起就可以认为说有一个任务队列在这,里边是当前银行中所有排号的客户。
任务队列中的都是已经完成的异步操作,而不是说注册一个异步任务就会被放在这个任务队列中,就像在银行中排号,如果叫到你的时候你不在,那么你当前的号牌就作废了,柜员会选择直接跳过进行下一个客户的业务处理,等你回来以后还需要重新取号

而且一个宏任务在执行的过程中,是可以添加一些微任务的,就像在柜台办理业务,你前边的一位老大爷可能在存款,在存款这个业务办理完以后,柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“最近P2P爆雷有点儿多,是不是要选择稳一些的理财呢”,然后告诉柜员说,要办一些理财的业务,这时候柜员肯定不能告诉老大爷说:“您再上后边取个号去,重新排队”。
所以本来快轮到你来办理业务,会因为老大爷临时添加的“理财业务”而往后推。
也许老大爷在办完理财以后还想 再办一个信用卡?或者 再买点儿纪念币
无论是什么需求,只要是柜员能够帮她办理的,都会在处理你的业务之前来做这些事情,这些都可以认为是微任务。

这就说明:你大爷永远是你大爷
在当前的微任务没有执行完成时,是不会执行下一个宏任务的。

引用:微任务、宏任务与Event-Loop - 贾顺名 - 博客园 (cnblogs.com)

 

posted @   铜须的编程生活  阅读(1783)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示