首先要知道JS是单线程,且分为同步任务和异步任务,同步任务就是即刻完成的任务,异步任务就是将来完成的任务。
请思考://代码输出的结果是什么?
请再思考: //代码输出的结果是什么?
所以我们知道js引擎第一步会将任务分成同步任务进入主线程,异步任务会进入Event table
图解如下:
第一步:console.log(1)进栈执行打印出1
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iMjFmZzgDMjBjNmV2Y2gjM4QWOwUWOwImYmRmMiFmNm9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
第二步:setTimeout是异步任务进入Event table哪里处理
第三步:console.log(3)进栈并执行打印出3
第四步:主线程空了之后,再执行异步的setTimeout
那么Event table 做了什么呢?
首先,我们要先了解,异步任务里又分为宏任务队列和微任务队列,且微任务队列只有一个,Event table会处理事件进入事件队列里的顺序(通过优先级判断和定时判断),并将宏任务放到宏任务队列里,微任务放到微任务队列里。
宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering
微任务:process.nextTick, Promise.then, MutationObserver.
那么eventloop是做些什么呢?
eventloop会不断的向主线程栈询问是否为空?如果为空的话就将任务队列中的微任务先推进主线成栈去执行,如果宏任务中产生了微任务,就把它放到微任务队列里,执行在微任务为空的情况下才可以继续执行宏任务,若宏任务里面还有异步任务就继续进入Event table分析再进入事件队列,直到所有栈和队列均为空。
我们再试试一道比较复杂的题目
console
第一步:先分同步任务和异步任务,同步任务必定会先执行,所以先打印出1,5,7,2,4,11,12,14 要注意 promise是一个同步任务,then方法里面才是个异步任务。同理,async标明了该函数里面有异步任务 await其实相当于promise.then{},例如 :
async
第二步:区分异步任务里的微任务和宏任务
//第一个 微任务
然后我们发现宏任务里 第三个比第二个执行更快,所以会更早进入宏任务队列。(宏任务是有优先级顺序的,优先级高的会先进入事件队列,setTimeout是优先级最低的宏任务)
这样我们就可以得到微任务队列 和 宏任务队列
宏任务队列:第三个 第二个
微任务队列:第一个 第四个
因为eventloop会先将微任务队列全部推进主进程执行栈中,所以先执行了第一个,第四个,即打印3,13,那么分析到这里结果就是1,5,7,2,4,11,12,14,3,13
任务队列就变成了
宏任务:第三个 第二个
微任务:空
第四步、执行宏任务队列里的第一个
//第三个 宏任务
直接打印出6,且没有产生其他异步任务,所以结果为1,5,7,2,4,11,12,14,3,13,6
第五步、继续执行宏任务
//第二个 宏任务
我们又可以得到接下去打印8,9,然后console.log(10)是一个异步任务,把它交给web API,然后放入了微队列
任务队列就变成了
宏任务:
微任务:console.log(10)
然后继续先执行微任务,就打印出了10,所以 顺序列表就为,1,5,7,2,4,11,12,14,3,13,6,8,910
所以最后结果为 1,5,7,2,4,11,12,14,3,13,6,8,9,10(注:这是浏览器结果,在其他环境下执行的可能是不一样的结果,一切以浏览器为准)
小结:画个流程图作为小结啦!