之前看过很多关于eventloop的文章,都是直接从js运行机制讲起,知道怎么回事了,但是对于全局的概念很懵逼,直到看了下面这篇文章,瞬间打通了任督二脉,建议反复阅读 juejin.im/post/684490…
js的运行机制
- js分为同步任务与异步任务
- 同步任务会在当前线程(js引擎线程)执行,形成一个任务栈
- 异步任务会放置于事件触发线程,待异步任务有了运行结果,就在其管理的任务队列放置一个事件
- 待js引擎线程中同步任务执行完毕,就会读取任务队列,将可以运行的任务放置到主线程中执行
异步任务又分为宏任务与微任务
- 执行一个宏任务
- 会首先判断当前有没有微任务,如果有的话,先清空微任务,然后再往下执行
- 如果当前没有微任务,就执行宏任务,碰到相应的微任务,放到微任务执行队列
- 宏任务执行完毕后进行渲染(GUI线程接管渲染)
- 渲染完毕后,判断微任务执行队列是否为空,不为空就清空所有的微任务再执行宏任务,否则就执行宏任务
宏任务:setTimeout、setInterval、setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)、I/O、UI Rendering
微任务:Process.nextTick(Node独有)、Promise、Object.observe(废弃)、MutationObserver
小试牛刀
setTimeout(function(){
console.log('定时器开始啦')
});
new Promise(function(resolve){
console.log('马上执行for循环啦');
for(var i = 0; i < 10000; i++){
i == 99 && resolve();
}
}).then(function(){
console.log('执行then函数啦')
});
console.log('代码执行结束');
马上执行for循环啦
代码执行结束
执行then函数啦
定时器开始啦
console.log('script start')
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
setTimeout(function() {
console.log('setTimeout')
}, 0)
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
console.log('script end')
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
1
7
8
2
4
5
9
11
12
setTimeout(function() {
console.log(2);
}, 0);
requestAnimationFrame(() => console.log(9));
9
2
执行优先级顺序
- 同步任务:最先执行。
- 微任务队列:在每次宏任务执行结束后立即执行所有微任务队列中的任务。如果在处理一个微任务期间又加入了新的微任务,新的微任务会在这次循环中继续执行(保持空闲条件下清空微任务队列)。
requestAnimationFrame:在所有微任务执行完毕后,并且在浏览器重新绘制之前执行。- 宏任务队列:事件循环每次 tick 执行一个宏任务,完成后再检查微任务队列。