今天看啥  ›  专栏  ›  影子同学

JavaScript在浏览器环境下的事件循环(Event Loop)

影子同学  · 掘金  ·  · 2019-04-10 07:35
阅读 39

JavaScript在浏览器环境下的事件循环(Event Loop)

这里主要记录在日常中对知识的学习,通过结合笔记与自身理解的方式尝试写下总结
文章对细节可能不会一一介绍解释,内容仅作参考
复制代码

一、背景

  1. JavaScript是一门单线程语言
  2. 单线程所带来的任务执行方式

二、同步任务与异步任务

  单线程就意味着,所有的任务都需要排队,当前一个任务结束时,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等待。 如果是因为计算量大,CPU忙不过来倒也正常,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。

  这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。于是,所有任务可以分成两种:

  1. 同步任务
  2. 异步任务

  在这里用一张图来说明:

  • 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table
  • 当异步任务完成时,Event Table会将对应的回调移入Event Queue中
  • JS引擎会持续不断检查主线程执行栈是否为空,当主线程内的任务全部执行完毕后,会去Event Queue读取排头第一个,进入到主线程执行
  • 上述过程不断重复,形成事件循环(Event Loop)

三、宏任务与微任务

  除了广义的同步任务和异步任务,会对任务有更精细的定义:

  • 宏任务:整体代码、setTimeout、setInterval
  • 微任务:Promise

  不同类型的任务会进入对应的Event Queue,比如setTimeout和setInterval会进入相同的Event Queue

  第一次进入整体代码(宏任务)后,开始第一遍循环,在主线程任务全部执行完毕后,会先去读取所有的微任务进行执行,然后再到宏任务,而宏任务里面或许又包含着宏任务与微任务。以此不断循环执行

  用一张图说明:

  举个栗子

setTimeout(function() {
    console.log('setTimeout')
})

new Promise(function(resolve) {
    console.log('promise')
    resolve()
}).then(function() {
    console.log('then')
})

console.log('console')
复制代码
  • 这段代码会作为宏任务,进入主线程
  • 先遇到setTimeout,将其放入Event Table,完成后会将其回调函数注册并放入到宏任务Event Queue
  • 接下来遇到了Promise,new Promise立即执行,然后遇到console.log('promise'),立即执行。then函数放入微任务Event Queue。
  • 遇到console.log('console'),立即执行
  • 整体代码作为第一个宏任务执行结束,接着查看是否有微任务?我们发现了then在微任务Event Queue里面,执行
  • 微任务全部执行完毕,第一轮事件循环结束,开始第二轮循环。从宏任务Event Queue发现有setTimeout对应的回调函数(多个宏任务的时候取队头),立即执行
  • 检查无可执行任务,结束



原文地址:访问原文地址
快照地址: 访问文章快照