Javascript 工作原理:Event loop

吐槽君 分类:javascript

转载:原文链接

什么是事件循环(Event loop)?

我们从一个奇怪的说法开始-尽管允许异步JavaScript代码(如setTimeout我),但是直到ES6为止,JavaScript本身实际上从未内置任何直接的异步概念。除了在任何给定的时刻执行程序的单个块之外,JavaScript引擎从未做过其他任何事情。

那么,谁告诉JS引擎执行您的程序块呢?实际上,JS引擎并不是孤立运行的,而是在托管环境中运行的,对于大多数开发人员而言,它是典型的Web浏览器或Node.js。实际上,如今,JavaScript已嵌入从机器人到灯泡的各种设备中。每个单独的设备代表JS Engine的不同类型的托管环境。

所有环境中的共同点是称为事件循环的内置机制,该机制每次调用JS Engine时都会处理程序中多个块的执行

这意味着JS引擎只是任何任意JS代码的按需执行环境。安排事件(JS代码执行)的时间是周围的环境。

因此,例如,当您的JavaScript程序发出Ajax请求以从服务器获取某些数据时,您在函数中设置了“response”代码(“callback”),然后JS引擎告诉托管环境:
“嘿,我现在暂时暂停执行,但是只要您完成该网络请求,并且有一些数据,请回叫此函数。”

然后,将浏览器设置为侦听来自网络的响应,并在有需要返回给您的内容时,将通过将其插入事件循环中来安排要执行的回调函数。
让我们看下图:

1_FA9NGxNB6-v1oI2qGEtlRQ.png

这些Web API是什么?本质上,它们是您无法访问的线程,您可以对其进行调用。它们是启动并发性的浏览器的组成部分。如果您是Node.js开发人员,则这些都是C ++ API。

那么事件循环到底是什么?

1_KGBiAxjeD9JT2j6KDo0zUg.png

事件循环有一个简单的工作-监听Call Stack 和Callback Queue。如果Call Stack 为空,则Event Loop将从queue中获取第一个事件,并将其推入Call Stack,从而有效地运行该事件。
这样的迭代在事件循环中称为tick每个事件只是一个函数回调。

console.log('Hi');
setTimeout(function cb1() { 
    console.log('cb1');
}, 5000);
console.log('Bye');
 

让我们“执行”这段代码,看看会发生什么:

  1. 状态很清楚。浏览器控制台已清除,并且调用堆栈为空。

1.png

  1. console.log('Hi')被添加到调用堆栈中

2.png

  1. console.log('Hi')被执行。

3.png

  1. console.log('Hi')从Call Stack.中删除。

4.png

  1. setTimeout(function cb1() { ... })被添加到Call Stack.中。

5.png

  1. setTimeout(function cb1() { ... })执行。浏览器将创建计时器作Web API的一部分。它会为您处理倒计时。

6.png

  1. setTimeout(function cb1() { ... })本身已经完成,并已从Call Stack.中删除。

7.png

  1. console.log('Bye')被添加到Call Stack.中。

8.png

  1. console.log('Bye')执行。

9.png

  1. console.log('Bye')从Call Stack中删除。

10.png

  1. 至少5000ms后,计时器完成,并将cb1回调推送到“Callback Queue”。

11.png

  1. Event loop cb1 从 Callback Queue 获取并将其推送到Call Stack.。

12.png

  1. cb1执行并添加console.log('cb1')到Call Stack.。

13.png

  1. console.log('cb1')执行。

14.png

  1. console.log('cb1')从Call Stack.中删除。

15.png

  1. cb1从Call Stack中删除。

16.png

快速回顾:

1_TozSrkk92l8ho6d8JxqF_w.gif

有趣的是,ES6指定了事件循环的工作方式,这意味着从技术上讲,它属于JS引擎职责范围之内,而JS引擎不再仅充当宿主环境角色。进行此更改的一个主要原因是在ES6中引入了Promises,因为后者需要访问对事件循环队列上的调度操作的直接,细粒度的控制(我们将在后面详细讨论)

setTimeout(…)如何工作的

重要的是要注意,setTimeout(…)它不会自动将callback放在 event loop queue中。它设置了一个计时器。当计时器到期时,环境会将您的callback放入event loop 中,以便将来的某个tick将其选中并执行。看一下这段代码:

setTimeout(myCallback, 1000);

这并不意味着myCallback将在1,000毫秒内执行,而是在1,000毫秒内myCallback将其添加到 event loop queue中。但是,queue中可能还包含其他较早添加的事件-您的回调将不得不等待。

看下面的代码:

setTimeout(function() {
    console.log('callback');
}, 0);
console.log('Bye');
 

尽管等待时间设置为0ms,但在浏览器控制台中的结果将是以下内容:

Hi
Bye
callback
 

回复

我来回复
  • 暂无回复内容