Vesper@之一

#

✨♻️ 可视化事件循环

这是一篇我自己翻译的前端基础博文,原作者是Lydia Hallie。 想看原文的小伙伴可以直接转到 ✨♻️ JavaScript Visualized: Event Loop

here we go!

正文开始👉


✨♻️JavaScript 可视化: 事件循环(Event Loop)

事件循环是那种每个JavaScript开发人员都必须以某种方式应对的事物之一,但一开始可能有点难以理解。作为一个视觉学习者,我想通过以低分辨率的gif形式向你解释它,因为现在是2019年,gif还是有些像素化和模糊。

但首先,什么是事件循环,为什么你应该关注它?

JavaScript是单线程的:一次只能运行一个任务。通常这没什么大不了的,但想象一下你正在运行一个需要30秒的任务…是的…在这个任务期间,我们需要等待30秒才能进行其他任何操作(JavaScript默认在浏览器的主线程上运行,因此整个UI都会被挂起)😬 这是2019年了,没有人想要一个慢速且无响应的网站。

幸运的是,浏览器给了我们一些JavaScript引擎自身没有提供的功能:Web API。这包括DOM APIsetTimeoutHTTP请求等等。这可以帮助我们创建一些异步、非阻塞的行为🚀

当我们调用一个函数时,它会被添加到一个叫做调用栈的地方。调用栈是JS引擎的一部分,这不是与特定浏览器相关的概念。它是一个栈,意味着它是先进后出的(想象一堆煎饼)。当一个函数返回一个值时,它会从栈中弹出👋

1

respond 函数返回一个 setTimeout 函数。setTimeout 由Web API提供,它允许我们延迟任务而不会阻塞主线程。我们传递给 setTimeout 函数的回调函数,箭头函数 () => { 返回 'Hey' } 被添加到Web API中。同时,setTimeout 函数和 respond 函数从栈中弹出,它们都已经返回了它们的值!

2

在Web API中,一个定时器会运行我们传递给它的第二个参数指定的时间长度,比如1000毫秒。回调函数不会立即被添加到调用栈,而是被传递给一个称为”队列”的东西。

3

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

现在,这是我们一直在等待的部分… 事件循环该做它唯一的任务了:连接队列和调用栈!如果调用栈为空,也就是说之前调用的所有函数都已经返回了值并从调用栈中弹出,那么队列中的第一个项会被添加到调用栈中。在这种情况下,没有其他函数被调用,这意味着在回调函数成为队列中的第一个项时,调用栈为空。

4

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

5

阅读文章是有趣的,但只有通过不断地实际应用和实践,才能真正对此感到舒适。尝试弄清楚如果我们运行以下代码会打印什么到控制台:

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

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

明白了吗?让我们快速看一下在浏览器中运行这段代码时发生了什么:

6

  1. 我们调用 bar 函数。bar 函数返回一个 setTimeout 函数。
  2. 我们传递给 setTimeout 的回调函数被添加到Web API中,setTimeout 函数和 bar 函数从调用栈中弹出。
  3. 定时器运行,在此期间调用了 foo 函数并打印了”First”。foo 函数返回(undefined),随后 baz 函数被调用,回调函数被添加到队列中。
  4. baz 函数打印了”Third”。事件循环在 baz 函数返回后发现调用栈为空,随后将回调函数添加到调用栈中。
  5. 回调函数打印了”Second”。

希望这篇文章能让你对事件循环更加舒适!如果仍然感到困惑,不用担心,最重要的是理解某些错误/行为可能出现的原因,以便有效地搜索正确的术语,并找到正确的 Stack Overflow 页面 💪🏼 如果有任何问题,请随时向我提问!


😊okk~ 翻译完了,纯人工翻译,希望能够帮到各位,如有纰漏,欢迎指正~