天天看点

js等待异步执行完再执行_带我彻底弄懂JS执行机制

首先要知道JS是单线程,且分为同步任务和异步任务,同步任务就是即刻完成的任务,异步任务就是将来完成的任务。

请思考:
//代码输出的结果是什么?
           
请再思考:
//代码输出的结果是什么?
           

所以我们知道js引擎第一步会将任务分成同步任务进入主线程,异步任务会进入Event table

图解如下:

第一步:console.log(1)进栈执行打印出1

js等待异步执行完再执行_带我彻底弄懂JS执行机制

第二步:setTimeout是异步任务进入Event table哪里处理

js等待异步执行完再执行_带我彻底弄懂JS执行机制

第三步:console.log(3)进栈并执行打印出3

js等待异步执行完再执行_带我彻底弄懂JS执行机制

第四步:主线程空了之后,再执行异步的setTimeout

那么Event table 做了什么呢?

首先,我们要先了解,异步任务里又分为宏任务队列和微任务队列,且微任务队列只有一个,Event table会处理事件进入事件队列里的顺序(通过优先级判断和定时判断),并将宏任务放到宏任务队列里,微任务放到微任务队列里。

宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering

微任务:process.nextTick, Promise.then, MutationObserver.

js等待异步执行完再执行_带我彻底弄懂JS执行机制

那么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(注:这是浏览器结果,在其他环境下执行的可能是不一样的结果,一切以浏览器为准)

小结:画个流程图作为小结啦!
js等待异步执行完再执行_带我彻底弄懂JS执行机制