小白从整体看Event Loop

239 阅读2分钟

之前看过很多关于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

执行优先级顺序
  1. 同步任务:最先执行。
  2. 微任务队列:在每次宏任务执行结束后立即执行所有微任务队列中的任务。如果在处理一个微任务期间又加入了新的微任务,新的微任务会在这次循环中继续执行(保持空闲条件下清空微任务队列)。
  3. requestAnimationFrame:在所有微任务执行完毕后,并且在浏览器重新绘制之前执行。
  4. 宏任务队列:事件循环每次 tick 执行一个宏任务,完成后再检查微任务队列。