深入理解JavaScript的事件循环(Event Loop)

 

一、什么是事件循环

JS的代码执行是基于一种事件循环的机制,之所以称作事件循环,MDN给出的解释为

因为它经常被用于类似如下的方式来实现

while (queue.waitForMessage()) {
  queue.processNextMessage();
}

如果当前没有任何消息queue.waitForMessage 会等待同步消息到达

我们可以把它当成一种程序结构的模型,处理的方案。更详细的描述可以查看 这篇文章

而JS的运行环境主要有两个:浏览器Node

在两个环境下的Event Loop实现是不一样的,在浏览器中基于 规范 来实现,不同浏览器可能有小小区别。在Node中基于 libuv 这个库来实现

 JS是单线程执行的,而基于事件循环模型,形成了基本没有阻塞(除了alert或同步XHR等操作)的状态

 

 二、Macrotask 与 Microtask

根据 规范,每个线程都有一个事件循环(Event Loop),在浏览器中除了主要的页面执行线程 外,Web worker是在一个新的线程中运行的,所以可以将其独立看待。

每个事件循环有至少一个任务队列(Task Queue,也可以称作Macrotask宏任务),各个任务队列中放置着不同来源(或者不同分类)的任务,可以让浏览器根据自己的实现来进行优先级排序

以及一个微任务队列(Microtask Queue),主要用于处理一些状态的改变,UI渲染工作之前的一些必要操作(可以防止多次无意义的UI渲染)

主线程的代码执行时,会将执行程序置入执行栈(Stack)中,执行完毕后出栈,另外有个堆空间(Heap),主要用于存储对象及一些非结构化的数据

深入理解JavaScript的事件循环(Event Loop)_第1张图片

一开始

宏任务与微任务队列里的任务随着:任务进栈、出栈、任务出队、进队之间交替着进行

从macrotask队列中取出一个任务处理,处理完成之后(此时执行栈应该是空的),从microtask队列中一个个按顺序取出所有任务进行处理,处理完成之后进入UI渲染后续工作

需要注意的是:microtask并不是在macrotask完成之后才会触发,在回调函数之后,只要执行栈是空的,就会执行microtask。也就是说,macrotask执行期间,执行栈可能是空的(比如在冒泡事件的处理时)

然后循环继续

常见的macrotask有:

  • run

你可能感兴趣的:(深入理解JavaScript的事件循环(Event Loop))