前言
(最后梳理比较简洁,在慢慢完善)
网上已有很多相关的js执行机制的文章了,那为啥还要写这个?
原因是其中一个机制大家有两套说法,不多BB直接上争议点 ↓ (不想看或已了解的直接跳到最后总结)
一.争议点
1.认为宏任务包含所有script代码的
这里可能有小伙伴不清楚宿主环境的概念,我简单描述下: 宿主环境是作为js运行的一个载体,常见的有浏览器、node.js等。
这个是笔者认同的,即:宏任务包含script主代码块
2.宏任务不包含所有script代码
虽然社区有人总喜欢列举 Promise.then、MutationObserver 是微任务(这里没列举完全),但是没捋清事件循环机制的前提下,死记硬背这些个“微任务”的话,面试官很容易借此挖坑请你跳。 所谓任务,浅显来说就是代码块开始执行的入口(确切地说,是函数栈的入口,但是栈的概念较为复杂,不表)。而在 JS 里,除了“script整体代码块”之外,所有代码块的入口都是“回调函数”,回调函数被注册到事件后不会马上被执行,而是保存在一个神秘的的地方,保存起来待执行的才能算“任务”,然后才有宏/微任务之分。 “script整体代码块”的特殊之处,在于它的入口不是回调函数,但是我们可以想象它被装在一个隐形的函数里,作为回调函数被注册到某个事件里(大概是它解析完成之后会触发的一个事件),这时候这个隐形的函数就成为了一个任务。
简单总结就是:异步代码才区分宏任务微任务
3.界限不清的
微任务:原生Promise(有些实现的promise将then方法放到了宏任务中)、process.nextTick、Object.observe(已废弃)、 MutationObserver 记住就行了。 作者:张倩qianniuer 链接:https://juejin.cn/post/6844903638238756878 来源:掘金
二.(宏)任务の真相
首先要说明宏任务其实一开始就是任务(task),为什么这么说呢?因为ES6新引入了Promise标准,同时浏览器实现上多了一个microtask微任务概念,作为对照才称宏任务。
贴上MDN文档定义
由此可以得出结论: 宏任务是包含JS主代码块的。
从区别上还可以很明显看出js事件的循环机制,每次宏任务迭代开始后加入到任务队列中的宏任务要等到下一次任务迭代开始执行。 而微任务中途加入的也会在这次事件循环结束前执行完。
三.知识点
先介绍定义,熟悉的可以直接跳过,看目录中的 完整关系总结
同步和异步
首先要知道js是单线程脚本语言。// 尽管h5提出了worker,但他也是基于单线程实现的
同步是js任务进入任务栈按顺序等待主线程执行的过程,简单来讲就是js从上到下代码的运行的过程,如果中间有个同步任务出现了死循环,那么浏览器可能就会出现js无响应...意思就是无法继续向下执行。
但是我们读取本地文件数据,或者获取服务器接口数据时,花费的时间无法确定,难道之后的js代码就要一直等待吗?这样会导致页面看起来非常卡顿,严重影响用户体验。这个时候就出现了异步,即不进入主线程任务栈,而是先进入event Table并注册回调函数,然后按顺序进入异步事件队列,在主线程的任务栈执行完后调用(队列先进先出,所以按注册函数进入队列的顺序来调用)。
// 文字看的累没关系,可以配合流程图食用
宏任务和微任务
宏任务(macrotask)
进入任务栈等待主线程执行的主代码块,包括从异步队列里加入到栈的,如setTimeout()、setInterval()的回调,其中不含异步队列中的微任务如Promise.then回调。
此时注意事件循环中(event loop)从异步队列加入到栈的宏任务是作为下一个事件来执行的,由于GUI渲染线程机制,每次事件循环后都会进行页面渲染,如下图:
常见宏任务有:
- 主代码块
- setTimeout
- setInterval
微任务(microtask)
是异步队列中,在当前这一次宏任务执行完后,页面渲染之前要执行的任务。
此时注意,即使当前微任务执行过程中,产生了新的微任务,也会在下一个宏任务开始执行之前且当前事件循环结束之前执行完所有的微任务。
常见微任务有:
- process.nextTick ()
- Promise
- Object.observe
四.完整关系总结
1.主体代码(第一次事件循环开始,所有的script代码)作为宏任务进入任务执行栈,但在主线程执行之前要做一系列操作判断。
2.判断当前任务是同步还是异步,同步的由主线程在任务栈中按先进后出顺序(先局部上下文,再全局上下文)执行,异步判断是宏任务还是微任务。
3.异步中的宏任务放入异步的宏任务event Table(异步队列分两种,宏任务队列和微任务队列,event Table也一样),微任务进入微任务event Table,在回调函数注册之后,再次进入它们对应的队列。
4.当主线程的任务执行完后,会检查微任务队列是否有任务,如果有就执行,如此循环,知道微任务队列没有任务。
5.当前事件的微任务执行完后,开始执行下一次事件,即会执行宏任务队列中的宏任务,如此循环下去,直到没有任务。
一点心里话
写的不咋样,哪里有问题请随意指出,或者有什么想讨论都可以留言,如果看不下去,点击 「硬核JS」一次搞懂JS运行机制看大佬的文章。觉得害行的点个赞鼓励一下呗。
辛苦各位看官,谢谢!
后续还会继续完善。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!