Javascript 事件循环的图示
Javascript 事件循环一开始让大多数开发人员感到有点困惑。
本文以低分辨率 GIF 进行直观解释,希望能帮助有需要的朋友。
但首先,什么是一系列事件以及为什么您应该关心?
JavaScript 是单线程的:一次只能运行一个任务。通常这不会是一个大问题,但现在想象一下您正在执行一个 30 秒的任务。
是的,对于这个任务,我们在做其他事情之前等待 30 秒(默认情况下,JavaScript 在主浏览器线程上运行,因此整个 UI 都关闭了)?现在是 2019 年,没有人想要一个缓慢且反应迟钝的网站。
幸运的是,浏览器为我们提供了一些 JavaScript 引擎本身没有的功能:Web API。这包括 DOM API、setTimeout、HTTP 请求等。这可以帮助我们创建异步、非阻塞行为。
当我们调用一个函数时,它会被添加到称为调用堆栈的东西中。调用堆栈是 JS 引擎的一部分,与浏览器无关。它是一个堆栈,意味着先进先出。当函数返回一个值时,它会从堆栈中弹出吗?
响应函数返回setTimeout函数。 setTimeout 是由 Web API 提供给我们的:它允许我们在不阻塞主线程的情况下延迟任务。我们传递给 setTimeout 函数的回调函数 arrow function() => {return ‘Hey’} 已添加到 Web API 中。同时,setTimeout函数和response函数从病毒中弹出,并且都返回值!
在 Web API 中,计时器一直运行,直到我们传递给它的第二个参数 1000ms。回调不会立即添加到调用堆栈中,而是传递到队列中。
这可能是一个令人困惑的部分:它并不意味着回调函数会在 1000 毫秒后添加到调用堆栈中(从而返回一个值)。它只是在 1000 毫秒后添加到队列中。但它是一个队列,函数必须等待轮到它!
现在是我们一直在等待的部分...是时候让事件循环完成其唯一的工作了:将队列连接到调用堆栈! 如果调用堆栈为空,则在所有先前调用的函数返回其值并从堆栈中弹出后,队列中的第一项将被添加到调用堆栈中。在这种情况下,不会调用其他函数,这意味着当回调函数成为队列中的第一项时,调用堆栈为空。
回调被添加到调用堆栈中,被调用,返回一个值,并弹出堆栈。
阅读这篇文章很有趣,但只有一遍又一遍地阅读才会完全满意。尝试找出运行以下命令时登录到控制台的内容:
const foo = () => console.log("第一个"); const bar = () => setTimeout(() => console.log("第二次"), 500); const baz = () => console.log("第三个"); 酒吧(); foo(); baz();
你明白吗?让我们快速看一下在浏览器中运行此代码时会发生什么:
- 我们调用bar,bar返回setTimeout函数。
- 传递给 SetTimeout 的回调被添加到 Web API,并且 setTimeout 函数和栏从调用堆栈中弹出。
- 当调用 foo 并打印 First 时,计时器就会运行。 foo 返回(未定义),调用 baz 并添加到回调队列中。
- baz 打印第三。事件循环看到baz返回后,调用堆栈为空,然后将回调添加到调用堆栈中。
- 回调是第二个打印的。
希望能帮助大家了解事件的循环!
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。