Js 的执行机制
程序在执行时 首先判断是同步任务还是异步任务 同步任务方法放到主线程中执行按照顺序一步一步的,如果是异步的首先现在 Event table 注册回调函数 ,如果是微任务的话就在微任务队列中 。一般来说在eventtable 注册的异步回调函数是宏任务。等到主线程的同步任务已经全部结束的时候,这时候先去微任务队列中去查找 先去执行微任务队列 清空微任务队列之后 这时候将 EventTbale中执行块的异步任务回调函数推入到事件队列中先执行。以上的操作反复执行就是事件队列。因为他可以算是一个死循环机制。
话不多说直接上图
很多人会问什么是微任务? 什么是宏任务
从我的理解就是 都是异步回调函数 只不过在主程序结束后先在微任务队列里查找 再去宏任务队列里查找,注意两个是不同的队列
微任务有哪些 process.nextTick promise.then() process.nextTick() 在微任务中都是最先执行的 这个只有node 环境中有。
SetTimeout setTimeInterval ajax 这些 属于宏任务
这里要特别注意的是 promise 函数 本身是同步的只是里面可以装异步回调函数而已。而且他是立即执行的。
好了接下来直接来一道面试题测试一波 你到底懂不懂?
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')
})
})
第一轮事件循环流程分析如下:
整体script作为第一个宏任务进入主线程,遇到console.log,输出1。
遇到setTimeout,其回调函数被分发到宏任务Event Queue中。我们暂且记为setTimeout1。
遇到process.nextTick(),其回调函数被分发到微任务Event Queue中。我们记为process1。
遇到Promise,new Promise直接执行,输出7。then被分发到微任务Event Queue中。我们记为then1。
又遇到了setTimeout,其回调函数被分发到宏任务Event Queue中,我们记为setTimeout2。
上表是第一轮事件循环宏任务结束时各Event Queue的情况,此时已经输出了1和7。
我们发现了process1和then1两个微任务。
执行process1,输出6。
执行then1,输出8。
好了,第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。那么第二轮时间循环从setTimeout1宏任务开始:
首先输出2。接下来遇到了process.nextTick(),同样将其分发到微任务Event Queue中,记为process2。new Promise立即执行输出4,then也分发到微任务Event Queue中,记为then2。
第二轮事件循环宏任务结束,我们发现有process2和then2两个微任务可以执行。
输出3。
输出5。
第二轮事件循环结束,第二轮输出2,4,3,5。
第三轮事件循环开始,此时只剩setTimeout2了,执行。
直接输出9。
将process.nextTick()分发到微任务Event Queue中。记为process3。
直接执行new Promise,输出11。
将then分发到微任务Event Queue中,记为then3。
第三轮事件循环宏任务执行结束,执行两个微任务process3和then3。
输出10。
输出12。
第三轮事件循环结束,第三轮输出9,11,10,12。
整段代码,共进行了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。
(请注意,node环境下的事件监听依赖libuv与前端环境不完全相同,输出顺序可能会有误差)