探究event-loop(事件循环)的真谛

95 阅读2分钟

在探究event-loop之前,我们得先聊一聊 进程 & 线程

  • 进程指的是cpu运行指令和保存上下文所需的时间

  • 线程是进程中更小的单位在,指的是一段指令执行所需的时间

  • 一个进程可以有一个也可以有多个线程

  • gpu是浏览器的绘制功能,就像一个画笔 css启动gpu

那么浏览器是有什么样的规则或者说属性呢?

浏览器新开一个tab页(属于进程)

  1. 渲染线程
  2. http请求线程
  3. js引擎线程
  4. 线程之间是可以一起工作的
  • 但是渲染线程和引擎线程是互斥的
  • JS是单线程的

优点:

  1. 节约内存
  2. 没有锁的概念,节约了上下文切换的时间
  3. 异步

  • 宏任务(macrotask): script , setTimeout ,setInterval, setImmediate, I/O, UI-rendering,

  • 微任务(microtask): promise.then(),MutationObserver,process.nextTick() 现在让我们来就来看看event-loop吧

Event-Loop

  1. 执行同步代码 (这属于宏任务)
  2. 当执行栈为空,查询是否有异步需要执行
  3. 执行微任务
  4. 如果有需要,会渲染页面
  5. 执行宏任务 (下一次event-loop) 接下来有一段js的代码,看看你是否可以看出来他的顺序是怎么样的
    setTimeout(() => {
   console.log(2);
    new Promise((resolve) => {
    console.log(4);
    resolve()
    setTimeout(() => {
      console.log(6);
    }) 
  }).then(() => {
    console.log(5);
  })
}, 1000)
console.log(3`);
如果你最后得出的结论是1、3、2、4、5、6的话恭喜你你已经初步了解了event-loop

接下来是一个困难版本的

async function async1() {  //函数声明不管也就是不执行
  await async2()         //浏览器给await开小灶提速
  console.log('saync1 end');  //被await挤入微任务队列
}
async function async2() {  //函数声明不管
  console.log('saync2 end');
}
async1()
setTimeout(function() {
  console.log('setTimeout');
}, 0)
new Promise((resolve) => {
  console.log('promise');
  resolve()
})
.then(() => {
  console.log('then1');
})
.then(() => {
  console.log('then2');
})
console.log('end'); 

如果你最终的结果是这样的话,那么你就完成了对事件循环真谛的探究

start saync2 end promise end saync1 end then1 then2 setTimeout