第一次录文章的话,是有点小激动!哈哈哈 主要是看了一篇关于朋友分享的Eventloop,然后加上他独特的见解,所以之后说的理解其实有一半受了他的感悟
如果有什么地方说的不合适的话,请多多发我消息,不胜感谢!
进入话题
首先理解的话我们一起思考思考问题,因为我觉着一旦出现某种方法,一定是为了解决某种事情才会出的方法。
1 . js为什么是单线程
* js是单线程操作我相信大家并不模式,但是为什么大佬要做成单线程内
* js刚开始主要是表格提交方面的需求,直接浏览器上做验证,直接过滤了一大片不合格的信息,大大的减少了服务器的压力,但是试想一下,如果多个用户再同时操作增删改,那js该判断执行增 还是删 还是改,顿时突然发现出门不用带伞了。(大头大头下雨不愁)头大了俩圈!
所以js是单线程的目的,但是紧接着问题又来了。
2 . 要是上一个任务一直没执行完怎么办?
* 就好像我去超市买东西,去前台付款,结果好家伙,前面那个人占着坑位疯狂输出,关键是我都不知道他还要多久才能结束战斗,然后我还要等他结束了我才能结账,此时心里有几个字差点憋不住了。
* 此时就有个好东西诞生了,同步任务 和 异步任务
* 而同步任务和异步任务最主要的差别就是,同步任务发起调用后,很快就可以得到结果,而异步任务是无法立即得到结果,比如请求接口,每个接口都会有一定的响应时间,根据网速、服务器等等因素决定,再比如定时器,它需要固定时间后才会返回结果。(这里的例子跟上面排队超市买东西是一样的)
众所周知队列是先进先出,但是我有种情况就是后进先出,没错!就是想插队!
比如队列先进入一个一小时的定时器,接着再进入一个请求接口函数,而如果根据进入队列的顺序执行的话,请求接口函数可能需要一个小时后才会响应数据。
因此浏览器就会将异步任务分为宏任务和微任务,然后按照事件循环的机制去执行,因此不同的任务会有不同的执行优先级。
事件循环 Eventloop
讲完了之前的一系列引出的问题,现在终于到了事件循环了!
事件循环具体流程:
-
从宏任务队列中,按照入队顺序,找到第一个执行的宏任务,放入调用栈,开始执行;
-
执行完该宏任务下所有同步任务后,即调用栈清空后,该宏任务被推出宏任务队列,然后微任务队列开始按照入队顺序,依次执行其中的微任务,直至微任务队列清空为止;
-
当微任务队列清空后,一个事件循环结束;
-
接着从宏任务队列中,找到下一个执行的宏任务,开始第二个事件循环,直至宏任务队列清空为止。
这里有几个重点:
-
当我们第一次执行的时候,解释器会将整体代码
script
放入宏任务队列中,因此事件循环是从第一个宏任务开始的; -
如果在执行微任务的过程中,产生新的微任务添加到微任务队列中,也需要一起清空;微任务队列没清空之前,是不会执行下一个宏任务的。
接下来就是我们最喜欢的看图环节了!
接下来,通过一个常见的面试题例子来模拟一下事件循环。
console.log("a")
setTimeout(function () {
console.log("b")
},0)
new Promise((resolve) => {
console.log("c")
resolve()
}).then(function () {
console.log("d")
}).then(function () {
console.log("e")
})
console.log("f")
// 执行结果 a c f d e b
首先,当代码执行的时候,整体代码script
被推入宏任务队列中,并开始执行该宏任务。
按照代码顺序,首先执行console.log("a")
。
该函数上下文被推入调用栈,执行完后,即移除调用栈。
接下来执行setTimeout()
,该函数上下文也进入调用栈中。
因为setTimeout
是一个宏任务,因此将其callback
函数推入宏任务队列中,然后该函数就被移除调用栈,继续往下执行。
紧接着是Promise
语句,先将其放入调用栈,然后接着往下执行。
执行console.log("c")
和resolve()
,这里就不多说了。
接着来到
new Promise().then()
方法,这是一个微任务,因此将其推入微任务队列中。
这时new Promise
语句已经执行结束了,就被移除调用栈。
接着做执行console.log('f')
。
这时候,script
宏任务已经执行结束了,因此被推出宏任务队列。
紧接着开始清空微任务队列了。首先执行的是Promise then
,因此它被推入调用栈中。
然后开始执行其中的console.log("d")
。
执行结束后,检测到后面还有一个then()
函数,因此将其推入微任务队列中。
此时第一个then()
函数已经执行结束了,就会移除调用栈和微任务队列。
此时微任务队列还没被清空,因此继续执行下一个微任务。
执行过程跟前面差不多,就不多说了。
此时微任务队列已经清空了,第一个事件循环已经结束了。
接下来执行下一个宏任务,即setTimeout callback
。
执行结束后,它也被移除宏任务队列和调用栈。
这时候微任务队列里面没有任务,因此第二个事件循环也结束了。
宏任务也被清空了,因此这段代码已经执行结束了。
然后突然就结束了!如果还有什么疑惑或者想跟我一起学习的话可以私聊或者评论下方,我一定可以看见!一定回复!用你帅气可爱美丽的双手点个赞是对小王最大的鼓励!