前置知识点(重要):
1.什么是事件循环:js是单线程语言,同个时间执行一件事(同步),但是他可以有一个异步队列,遇到异步操作(比如说ajax这种阻塞时间很久的事情)把它们先放入异步队列,并且继续往下执行,当同步队列执行完了,他就会去异步队列里面找刚才存放起来的事件,然后按顺序执行他们。
2.异步队列(异步任务)又包含宏任务和微任务,微任务先与宏任务执行
宏任务有:
微任务有:
3.同为微任务的Promise与process.nextTick(callback),先执行后者(process.nextTick(callback)当下一轮事件开始循环的时候第一时间执行他的callback)
下图为他们之间的关系图:
通过一个例子来解释执行整个事件循环,与同步异步,宏任务微任务执行顺序
console.log('1');setTimeout(function() {console.log('2');process.nextTick(function() {console.log('3');})new Promise(function(resolve) {console.log('4');resolve();}).then(function() {console.log('5')})})process.nextTick(function() {console.log('6');})new Promise(function(resolve) {console.log('7');resolve();}).then(function() {console.log('8')})setTimeout(function() {console.log('9');process.nextTick(function() {console.log('10');})new Promise(function(resolve) {console.log('11');resolve();}).then(function() {console.log('12')})})//
1.第一轮事件循环流程分析如下:(第一轮描述详细一点,接下去都差不多)
– 进入主线程,遇到console.log,输出1。
遇到setTimeout,其回调函数被分发到宏任务Event Queue中。我们暂且记为setTimeout1。
– 遇到process.nextTick(),其回调函数被分发到微任务Event Queue中。我们记为process1。
– 遇到Promise,new Promise(是同步,then才是异步)直接执行,输出7。then(Promise中then是异步)被分发到微任务Event Queue中。我们记为then1。
– 又遇到了setTimeout,其回调函数被分发到宏任务Event Queue中,我们记为setTimeout2。
上表是第一轮事件循环宏任务结束时各Event Queue的情况,此时已经输出了1和7。
我们发现了process1和then1两个微任务。
执行process1,输出6。
执行then1,输出8。
好了,第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。
2.第二轮时间循环从setTimeout1宏任务开始:
首先输出2。接下来遇到了process.nextTick(),同样将其分发到微任务Event Queue中,记为process2。
new Promise立即执行输出4,then也分发到微任务Event Queue中,记为then2
如表所示:这一轮取出setTimeout1,分析发现两个微任务,则先执行这两个微任务。
3.第三轮宏任务setTimeout2开始执行
如表所示:这一轮取出setTimeout2,分析发现两个微任务,则先执行这两个微任务process3和then3。
输出10。
输出12。
第三轮事件循环结束,第三轮输出9,11,10,12。
整段代码,共进行了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。(请注意,node环境下的事件监听依赖libuv与前端环境不完全相同,输出顺序可能会有误差)
图解js执行机制–事件循环
首先,整体的script(作为第一个宏任务)开始执行的时候,会把所有代码分为同步任务、异步任务两部分
同步任务会直接进入主线程依次执行
异步任务会再分为宏任务和微任务
宏任务进入到Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中
微任务也会进入到另一个Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中
当主线程内的任务执行完毕,主线程为空时,会检查微任务的Event Queue,如果有任务,就全部执行,如果没有就执行下一个宏任务
上述过程会不断重复,这就是Event Loop,比较完整的事件循环