先说一下概念:
由于js是单线程的语言,一次只能执行一项事件,js在浏览器这个宿主环境中运行.用户交互,定时器,网络请求等.浏览器中的事件会产生对应的任务,当任务累积时,便会将其排列到任务队列中,浏览器的主线程依次取出执行的过程不断重复从而形成一个循环,则称为事件循环,Eventloop.
任务队列中执行的代码也是有先后顺序的,但是在某些场景需要优先执行部分代码,所以分为宏任务与微任务.
比较常见一些的宏任务有:script,定时器,dom事件,ajax.
微任务有:promise.then()等
宏任务,微任务与同步代码的执行顺序应为:
先执行第一个宏任务, 然后同步任务, 然后微任务, 然后下一个宏任务如此循环, 直到所有代码执行完毕.
下面看一个小案例
<script>
console.log(1);
setTimeout(() => {
console.log(2);
}, 2000)
console.log(3);
</script>
输出结果为:
//1,3,2
运行顺序为:
/*script为整体宏任务,
定时器作为第二宏任务在2秒后加入任务队列,,按照代码执行顺序先打印1,再打印3,
scrpit这个任务执行完毕,浏览器主线程继续执行第二个宏任务,打印2*/
即任务队列中没有微任务,宏任务便依次排序,由主线程执行.
再来一个稍微复杂一些的
<script>
console.log(1)
setTimeout(function () {
console.log(2)
new Promise(function (resolve) {
console.log(3)
resolve()
}).then(function () {
console.log(4)
})
})
new Promise(function (resolve) {
console.log(5)
resolve()
}).then(function () {
console.log(6)
})
setTimeout(function () {
console.log(7)
new Promise(function (resolve) {
console.log(8)
resolve()
}).then(function () {
console.log(9)
})
})
console.log(10)
</script>
页面输出结果为:
//1,5,10,6,2,3,4,7,8,9
运行顺序为:
/*
script为宏任务首先运行,接着走第一行
页面输出为1
已知第二行定时器也为宏任务,便排在script后,那么先不执行
接下来代码走到new promise对象这,那么进入到函数内
页面输出为5
并标记为成功,promise的实例方法.then(log(6)),将其放入微任务队列等待执行
将下一个定时器也排入宏任务队列内暂不执行
此时走到最后一行
页面输出10
此时scrpit的宏任务走完,那么浏览器的主线程开始检查微任务队列并开始执行
页面输出6
当主线程检测到微任务队列没有剩余任务执行,那么开始走第二个宏任务定时器,
页面输出2,
下一行为new promise对象,则进入函数
页面输出3
并标记成功,promise的实例方法.then(log(4)),将其放入微任务队列等待执行
此时主线程将第二个定时器宏任务执完毕,但检测到微任务队列,便执行微任务
页面输出4
微任务执行完毕,队列清空,主线程接着执行第三个定时器
页面输出7
同理下一行为new promise,进入函数
页面输出8
并标记成功,promise的实例方法.then(log(9)),将其放入微任务队列等待执行
此时主线程将第三个定时器宏任务执完毕,但检测到微任务队列,便执行微任务
页面输出9
所有最后得出页面输出结尾为1,5,10,6,2,3,4,7,8,9
*/
以上简单的将事件循环中的微任务与宏任务运用了一番,大家可以多整理一下.