搞懂JS的事件循环(EVent Loop) 和微任务/宏任务

89 阅读2分钟

搞懂JS的事件循环(EVent Loop) 和微任务/宏任务

事件循环机制EventLoop

首先大家都知道JS是一门单线程的语言,所有的任务都是在一个线程上完成的。而我们知道,有一些像I/O,网络请求等等的操作可能会特别耗时,如果程序使用"同步模式"等到任务返回再继续执行,就会使得整个任务的执行特别缓慢,运行过程大部分事件都在等待耗时操作的完成,效率特别低。

为了解决这个问题,于是就有了事件循环(Event Loop) 这样的概念,简单来说就是在程序本身运行的主线程会形成一个"执行栈",除此之外,设立一个"任务队列",每当有异步任务完成之后,就会在"任务队列"中放置一个事件,当"执行栈"所有的任务都完成之后,会去"任务队列"中看有没有事件,有的话就放到"执行栈"中执行。

这个过程会不断重复,这种机制就被称为事件循环(Event Loop)机制。

微任务和宏任务

宏任务可以被理解为每次"执行栈"中所执行的代码,而浏览器会在每次宏任务执行结束后,在下一个宏任务执行开始前,对页面进行渲染,而宏任务包括:

  • script(整体代码)
  • setTimeout
  • setInterval
  • I/O
  • UI交互事件
  • postMessage
  • MessageChannel
  • setImmediate
  • UI rendering

微任务,可以理解是在当前"执行栈"中的任务执行结束后立即执行的任务。而且早于页面渲染和取任务队列中的任务。微任务包括:

  • Promise.then
  • Object.observe
  • MutaionObserver
  • process.nextTick

他们的运行机制是这样的:

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)