Javascript 中的 Event Loop

前言

Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。

什么是 Event Loop?

image.png

Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。

想要理解Event Loop,就要从程序的运行模式讲起。运行以后的程序叫做"进程"(process),一般情况下,一个进程一次只能执行一个任务。

如果有很多任务需要执行,不外乎三种解决方法。

(1)排队。因为一个进程一次只能执行一个任务,只好等前面的任务执行完了,再执行后面的任务。

(2)新建进程。使用fork命令,为每个任务新建一个进程。

(3)新建线程。因为进程太耗费资源,所以如今的程序往往允许一个进程包含多个线程,由线程去完成任务。

以JavaScript语言为例,它是一种单线程语言,所有任务都在一个线程上完成,即采用上面的第一种方法。一旦遇到大量任务或者遇到一个耗时的任务,网页就会出现"假死",因为JavaScript停不下来,也就无法响应用户的行为。

你也许会问,JavaScript为什么是单线程,难道不能实现为多线程吗?
这跟历史有关系。JavaScript从诞生起就是单线程。原因大概是不想让浏览器变得太复杂,因为多线程需要共享资源、且有可能修改彼此的运行结果,对于一种网页脚本语言来说,这就太复杂了。后来就约定俗成,JavaScript为一种单线程语言。(Worker API可以实现多线程,但是JavaScript本身始终是单线程的。)

Event Loop 是什么?

Wikipedia中对Event Loop的描述为:

在计算机科学中,Event Loop是指一个用于等待和发送消息和事件的程序结构(In computer science, the 
event loop is a programming construct or design pattern that waits for and dispatches events 
or messages in a program. )

简单来说,就是在除主线程之外设置一个用于协调主线程中和其他线程的一个“辅助线程”的结构

Event Loop的具体内容

在完整讲述Event Loop之前,需要先讲解一下Javascript的运行机制;在javascript中,代码(程序)的执行一般遵循一下的机制:

  1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
  2. 主线程之外还存在“任务队列/调用队列”(task queue),用于存放等待执行的任务
  3. 每当“执行栈”中的同步任务执行完成后,主线程将会将“任务队列”中的第一个任务加入“执行栈”
v2-55c58a901cf835e5e308e4360694505f_720w.jpg

执行栈

当我们调用一个方法的时候,js会生成一个与这个方法相对应的执行环境,也叫执行上下文,这个执行环境存在着这个方法的私有作用域、参数、this对象等等。因为js是单线程的,同一时间只能执行一个方法,所以当一系列的方法被依次调用的时候,js会先解析这些方法,把其中的同步任务按照执行顺序排队到一个地方,这个地方叫做执行栈。

任务队列

当我们发出一个ajax请求,他并不会立刻返回结果,为了防止浏览器出现假死或者空白,主线程会把这个异步任务挂起(pending),继续执行执行栈中的其他任务,等异步任务返回结果后,js会将这个异步任务按照执行顺序,加入到与执行栈不同的另一个队列,也就是事件队列。

以上的事件循环过程只是一个宏观的表述,实际上异步任务之间也不相同,执行优先级也有区别。不同的异步任务被分为两类:宏任务(macro task)和微任务(micro task)。我们将经常遇到的异步任务进行分类如下:

在javascript中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask)。

其中,宏任务指的是:

  • script全部代码
  • setTimeout
  • setInterval
  • setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN
  • I/O
  • UI Rendering

微任务指:

  • Process.nextTick(Node独有)
  • Promise
  • Object.observe(废弃)
  • MutationObserver(具体使用方式查看这里

按照前面的介绍,异步任务会按照执行完成的顺序添加到任务队列中;事实上,根据异步任务的不同类型,这个任务最终会分别添加到宏任务队列和微任务队列中去

当执行栈中的任务清空,主线程会先检查微任务队列中是否有任务,如果有,就将微任务队列中的任务依次执行,直到微任务队列为空,之后再检查宏任务队列中是否有任务,如果有,则每次取出第一个宏任务加入到执行栈中,之后再清空执行栈,检查微任务,以此循环... ...

简单来说,就是微任务队列中的所有任务的优先级都高于宏任务队列中的任务

v2-4f6d315afb5bab4f7ab66be4eb6f7ffb_720w.jpg
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容