1、什么是Event Loop
我们都知道,js是单线程,同一个时间只能做同一件事,所有的任务都需要排队,前一个任务完成,才会执行后一个任务,如果前一个任务耗时很长,后一个任务就不得不一直等着。
Event Loop也就是事件循环,主线程只会做一件事情,就是从消息队列里面取消息,执行完成消息,再取消息,再执行完成消息,当队列为空时,就会等待,直到队列变成非空,这种机制就叫做事件循环机制,取一个消息并执行的过程叫一次循环。
2、关于MacroTask 和 MicroTask(宏任务和微任务)
- 一张图展示js中的事件循环
- 一次事件循环
先运行
macroTask宏任务队列中的一个,然后运行microTask微任务队列中的所有任务。接着开始下一次循环(这个只是针对宏任务和为任务,一次完整的事件循环会比这个复杂的多) 其中macroTask和microTask是两种任务队列,相比而言,大家更熟悉的一个词是任务队列(task queue,其实就是macroTask),大家更熟悉的关于事件循环的机制说法大概是:主进程执行完了之后,每次从任务队列里取一个任务执行。但是promise出现之后,这个说法就不太准确了。 js引擎将这两种队列有不同的处理,引擎会把任务队列分门别类,一部分归位macroTask,另一部分归位microTask;
-
例如:
macroTask类:setTimeout、setInterval、setImmediate、requestAnimationFrame、I/O、UI renderingmicroTask类:process.nextTick, Promise, Object.observe, MutationObserver -
以下代码输出??? 两种任务队列的运行方式
console.log('main1');
process.nextTick(function() {
console.log('process.nextTick1');
});
setTimeout(function() {
console.log('setTimeout');
process.nextTick(function() {
console.log('process.nextTick2');
});
}, 0);
new Promise(function(resolve, reject) {
console.log('promise');
resolve();
}).then(function() {
console.log('promise then');
});
console.log('main2');
答案:main1、promise、main2、 process.nextTick1、 promise then、setTimeout、process.nextTick2
在第一个循环里,process.nextTick1和promise then这两个microTask(微任务)是在setTimeout这个macroTask(宏任务)之前输出的。这是为什么??
因为主进程的代码也属于
macroTask,(main1,promise,main2)都是同步代码,先执行完了,自然会去执行microTask(process.nextTick1,promise then)。这是第一个循环,之后的setTimeout和process.nextTick2属于第二个循环。
在html规范中,在处理了macroTask和microTask之后,会进行一次update the rendering,就是会进行一次ui的渲染。