Event Loop 事件轮询

800 阅读3分钟

为什么JavaScript是单线程

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

任务队列

JavaScript的主要用途是与用户互动所以为了避免复杂性javascript语言的核心特征就是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务

Micro-Task 与 Macro-Task

事件循环中的异步队列有两种:macro(宏任务)队列和 micro(微任务)队列

常见的 macro-task 比如: setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等

常见的 micro-task 比如: process.nextTick、Promise、MutationObserver 等

image.png

  • 栈(stack),函数调用堆栈
  • 堆(heap),内存区,用于存储对象(这个目前不是很重要先不管)
  • 队列(queue),待处理消息队列,每一个消息都关联着一个用以处理这个消息的函数

JavaScript事件模型是怎么工作的

js是什么

I am a single-threaded non-blocking asynchronous concurrent runtime. js是一个单线程的不阻塞的一个异步的运行时

js是怎么工作的

I have a call-stack, an even-loop,a callback queue some other apis and stuff 我有一个调用栈一个事件模型一个callback的任务队列,一些apis还有一些其余的一些附加功能

以chrome浏览器为例,不同浏览器机制可能会不同 image.png

Event Loop

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)

整体运行过程

image.png

  1. 主线程执行同步代码,执行过程会产生对应的函数调用栈stack,如果碰到有异步事件,如发起ajax请求,则提交给对应的异步模块处理,当异步任务有结果时,异步模块负责在消息队列中添加待处理的消息
  2. 当同步任务处理完成,函数调用栈清空时,主线程检查消息队列queue:如果消息队列不为空,那么从消息队列头部取出一个待处理的消息,进入主线程
  3. 主线程重复以上过程 上述过程循环执行,所以称为事件循环(Event Loop)

参考文章