event loop 是异步回调的实现原理

js 代码的执行过程

  • 从前到后,一行一行执行
  • 如果某一行执行报错,则停止下面代码的执行
  • 先把同步代码执行完,再执行异步

event loop 图解

以下方代码为例:

js【详解】event loop(事件循环/事件轮询)_javascript

第1步 将第 1 行代码放入调用栈

将要执行第1行代码放入调用栈(call stack)中

js【详解】event loop(事件循环/事件轮询)_Web_02

第2步 执行第 1 行代码,清空调用栈

执行第1行代码,在浏览器中打印 Hi,并清空调用栈

js【详解】event loop(事件循环/事件轮询)_javascript_03


js【详解】event loop(事件循环/事件轮询)_回调函数_04

第3步 将第 3 行代码放入调用栈

js【详解】event loop(事件循环/事件轮询)_javascript_05

第4步 执行第 3 行代码,设置定时器,清空调用栈

执行第3行代码,发现是一个定时任务,于是在 Web APIs 中设置一个回调函数为 cb 1 的定时器,清空调用栈

js【详解】event loop(事件循环/事件轮询)_调用栈_06

第5步 将第 7 行代码放入调用栈

js【详解】event loop(事件循环/事件轮询)_javascript_07

第6步 执行第 7 行代码,清空调用栈,开始事件轮询

执行第7行代码,在浏览器中打印 Bye,并清空调用栈

js【详解】event loop(事件循环/事件轮询)_回调函数_08


此时同步代码已执行完,开始事件轮询(即不断询问回调队列中是否存在可执行代码)

js【详解】event loop(事件循环/事件轮询)_调用栈_09


事件轮询会一直进行,直到整个js代码不再运行(如页面被销毁)。

第7步 将定时器的回调函数放入回调队列

本例中,第3行代码设置的定时器是 5 秒,则从第4步设置定时器开始记时,5秒后,将 Web APIS 中的定时器的回调函数放入回调队列(Callback Queue)中

js【详解】event loop(事件循环/事件轮询)_Web_10

第8步 事件轮询将定时器的回调函数放入调用栈

定时器的回调函数放入回调队列的那一刻,就会被事件轮询到(若回调队列已有多个回调函数,则会按先进先出的原则依次放入调用栈),并放入调用栈

js【详解】event loop(事件循环/事件轮询)_调用栈_11

第9步 将第 4 行代码放入调用栈

js【详解】event loop(事件循环/事件轮询)_调用栈_12

第10步 执行第 4 行代码,移除调用栈中的第 4 行代码

执行第4行代码,在浏览器中打印 cb1,将第4行代码从调用栈中移除

js【详解】event loop(事件循环/事件轮询)_调用栈_13


js【详解】event loop(事件循环/事件轮询)_调用栈_14

第11步 清空调用栈,全部代码执行完毕

因回调函数 cb1内的代码已执行完毕,函数cb1 也被移出调用栈

js【详解】event loop(事件循环/事件轮询)_调用栈_15