《译》惊艳!动态图演示 - 事件循环 Event Loop

1,819 阅读4分钟

前言

对于事件循环,这是每个 JavaScript 开发人员必然会遇到或者需要理解的内容之一。

但是对于初级开发者来说,理解起来可能有些混乱。

因为我是一个视觉学习者,所以我通过低分辨率 gif 图的可视化方式来帮助你理解它。

事件循环

但是首先,事件循环是什么,为什么要关心呢?

JavaScript 是 单线程的:一次只能运行一个任务。

通常,这没什么大不了的,但是现在想象你正在运行一个耗时 30 秒的任务。

在此任务中,我们等待 30 秒才能进行其他任何操作(默认情况下,JavaScript 在浏览器的主线程上运行,因此整个用户界面都停滞了)😬 。

都到 2020 年了,没有人想停留在一个速度慢,交互反应迟钝的网站。

幸运的是,浏览器为我们提供了JavaScript 引擎本身不提供的一些功能:Web API。

这包括 DOM API,setTimeout HTTP 请求等,这可以帮助我们创建一些异步的,非阻塞的行为。

当我们调用一个函数时,它会被添加到称为 调用栈 的数据结构中。

调用栈是 JS 引擎的一部分,这不是特定于浏览器的。

它是一个调用栈,这意味着它是 先进先出 的(例如一堆煎饼)。

当一个函数返回一个值时,它会从调用栈中弹出 👋。

respond 函数返回一个 setTimeout 函数。

setTimeout 由 Web API 提供给我们:它让我们拖延的任务,而不会阻塞主线程。

我们传递给该 setTimeout 函数的回调函数,箭头函数 () => { return "Hey" } 已添加到 Web API。

同时,该 setTimeout 函数和 response 函数从调用栈中弹出,它们都返回了它们的值!

在 Web API中,计时器的运行时间与我们传递给它的第二个参数 1000ms 一样长。回调不会立即添加到调用栈中,而是会传递给称为队列的东西。

这可能是一个令人困惑的部分:这并不意味着在 1000 毫秒后将回调函数添加到调用栈中(从而返回一个值)!它只是在 1000 毫秒后添加到 队列中。但这是一个队列,该功能必须等待轮到它!

接下为是我们一直在等待的重点内容……

让事件循环执行其唯一的任务了:将队列与调用栈连接起来!如果调用栈为 ,那么如果所有先前调用的函数都返回了它们的值并已从堆栈中弹出,则队列中的 第一项 将添加到调用栈中,在这种情况下,没有其他函数被调用,这意味着当回调函数成为队列中的第一项时,调用栈为空。

回调被添加到调用栈中,被调用,并返回一个值,并从调用栈中弹出。


例子

阅读一篇文章很有趣,但是通过反复地实际操作,你会对此理解得更深。

如果运行以下 js,请想一下控制台会输出什么内容:

const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");

bar();
foo();
baz();

想出答案了吗?

让我们快速看一下在浏览器中运行此代码时发生的过程:

  1. 我们调用 barbar 返回一个 setTimeout 函数。

  2. 我们传递给的回调 setTimeout 被添加到 Web API,该 setTimeout 函数中,并 bar 从调用堆栈中弹出。

  3. 计时器运行,同时 foo 调用并记录 Firstfoo 返回(未定义),baz 被调用,并将回调添加到队列中。

  4. baz 输出 Third,事件循环看到 baz 返回后调用栈为空,然后将回调添加到调用栈。

  5. 回调再打印出 Second


希望这会使你对事件循环的理解更加清析!最重要的是 了解某些错误 / 行为可能从何而来

当遇到不明白的地方时,也能 高效地Google 上搜索正确的关键字 ,并能搜索到正确的答案 💪🏼 。

最后

外国友人技术博客的语言表达的方式和风格、与国人的还是有很大差别的啊。

姐妹篇:惊艳!可视化的 js:动态图演示 Promises & Async/Await 的过程!

翻译了两篇文章,还是蛮有趣的 😇,瞬间感觉自己的英文水平高达 8 级了啦 (白日梦 🤩)。

推荐阅读: 通过10 个实例小练习,快速入门熟练 Vue3 核心新特性

支持一下下👇