事件循环机制?
事件循环是由一个队列组成的,异步任务的回调遵循先进先出,在JS引擎空闲时会一轮一轮地被取出,所以被叫做循环。
根据队列中任务的不同,分为宏任务和微任务。
事件循环由宏任务和在执行宏任务期间产生的所有微任务组成。完成当下的宏任务后,会立刻执行所有在此期间入队的微任务。浏览器的事件循环由一个宏任务队列+多个微任务队列组成。
首先,执行第一个宏任务:全局Script脚本。产生的的宏任务和微任务进入各自的队列中。执行完Script后,把当前的微任务队列清空。完成一次事件循环。
接着再取出一个宏任务,同样把在此期间产生的回调入队。再把当前的微任务队列清空。以此往复。
宏任务队列只有一个,而每一个宏任务都有一个自己的微任务队列,每轮循环都是由一个宏任务+多个微任务组成。
微任务插队:打印的结果不是从1到4,而是先执行第四个回调函数,再执行第三个,因为它是一个微任务,比第三个回调函数有更高优先级。
Promise.resolve().then(()=>{
console.log('第一个回调函数:微任务1')
setTimeout(()=>{
console.log('第三个回调函数:宏任务2')
},0)
})
setTimeout(()=>{
console.log('第二个回调函数:宏任务1')
Promise.resolve().then(()=>{
console.log('第四个回调函数:微任务2')
})
},0)
// 第一个回调函数:微任务1
// 第二个回调函数:宏任务1
// 第四个回调函数:微任务2
// 第三个回调函数:宏任务2
宏任务/微任务?
宏任务和微任务的区别?
先执行微任务,再执行宏任务;宏任务是由宿主环境来发起的(浏览器/node)任务,微任务是由js引擎来发起的任务。
<script>
console.log('start');
setTimeout(()=>{
console.log('setTimeout')
},1000);
Promise.resolve().then(()=>{
console.log('promise')
})
console.log('end');
</script>
输出顺序为:start--end--promise-- setTimeOut,因为js的执行机制就是先把所有的同步任务都执行完,再去执行异步任务,其中start和end都是同步任务,从上至下最先执行,promise和etTimeout是异步任务,而promise是微任务,所以先执行promise。
宏任务有哪些?微任务有哪些?
微任务:promise、async/await(*promise本身是同步的,但是它的回调函数.then().catch()是异步的。)
宏任务:setTimeout、setInterval、DOM事件、AJAX、script代码块
宏任务、微任务和DOM渲染之间的关系?
同步任务 -> 微任务 -> DOM渲染 -> 宏任务
为什么要把异步任务拆分成宏任务和微任务?
微任务是线程之间的切换,速度快。不用进行上下文切换,可以快速的一次性做完所有的微任务。
宏任务是进程之间的切换,速度慢,且每次执行需要切换上下文。因此一个Eventloop中只执行一个宏任务。
而区分微任务和宏任务的根本原因是为了插队。由于微任务执行快,一次性可以执行很多个,在当前宏任务执行后立刻清空微任务可以达到伪同步的效果,这对视图渲染效果起到至关重要的作用。微任务的出现,使得在宏任务执行完,到浏览器渲染之前,可以在这个阶段插入任务的能力。
反观如果不区分微任务和宏任务,那么新注册的任务不得不等到下一个宏任务结束后,才能执行。