介绍
大家好!
今天,正如标题所说,我将讨论事件循环。
这不是面试官经常直接询问的话题(我只记得有两次他们让我解释事件循环)。但是,在大多数采访中,他们会提出与之相关的问题。例如:
- “如果我这样做……应该有什么行为?”
- “如果我的代码如下所示,输出会是什么?”
- “为什么这段代码会产生这样的输出?”
如果您了解事件循环的工作原理,那么所有这些问题都会更容易回答。
老实说:这个话题不是我最喜欢的。我更喜欢询问有关代码行为的问题,而不是解释事件循环如何连续工作 10 分钟。?
让我们开始吧! ?
## 问题
1.什么是事件循环?
2. 示例
什么是事件循环?
简短回答:
事件循环负责处理 JavaScript 运行时中的异步任务。
说实话,我认为这个答案不足以满足面试官询问事件循环的好奇心。因此,在这篇文章中,我想更深入地探讨这个主题。
不仅仅是了解概念,了解如何它的工作原理也很重要。这就是为什么我在最后添加了一些示例。
理论
什么是事件循环?
JavaScript 有一个基于事件循环的运行时,负责处理任务。每种语言都有独特的运行时,需要注意的重要一点是 JavaScript 是单线程。
单线程是什么意思?
单线程意味着JavaScript 一次只能处理一项任务。这就是为什么事件循环在 JavaScript 中如此重要;尽管存在单线程限制,它仍然有助于有效地管理任务。
运行时的组成部分
为了更好地理解事件循环,我们首先看一下它的主要组成部分:
调用栈
调用堆栈是一种数据结构,用于跟踪我们调用的函数。你可以把它想象成一堆盘子:当一个函数被调用时,它被添加到堆栈中,当它完成时,它被从堆栈中删除。
调用堆栈遵循 LIFO(后进先出) 原则,这意味着 JavaScript 按照函数的堆叠顺序执行函数 — 从最上面的项到底部,一个位于一次(记住,JavaScript 是单线程的)。
队列
在 JavaScript 的运行时中,我们有队列,它保存要处理的任务列表。这些队列中的任务会等待,直到调用堆栈为空。
任务队列(或回调队列):此队列存储诸如 setTimeout() 和 setInterval() 调用之类的任务。这里的任务是在调用堆栈为空并且微任务队列中的所有任务都处理完之后进行处理的。在 MDN 上查看存储在此队列中的任务的更多示例。
微任务队列: 该队列的优先级高于任务队列。它包括微任务(例如 Promise 回调)和异步函数(例如 process.nextTick() 和异步函数)。
任务队列以FIFO(先进先出)为基础工作,这意味着任务按照添加的顺序进行处理,但仅在微任务之后进行队列已空。
事件循环
事件循环是一种管理异步代码执行的机制。它观察调用堆栈以及调用堆栈和队列(任务队列和微任务队列)之间的协调,以保持代码顺利运行。
它是如何运作的?
让我们一步步过一遍事件循环过程。请参阅下图以获得直观表示。
在此示例中:
- 调用堆栈只有一个功能。
- 微任务队列有两条消息。
- 任务队列有一条消息。
第 1 步:处理调用堆栈
- 事件循环从查看调用堆栈开始。
- 它在堆栈中找到一个函数并开始执行它。
- 此函数完成后,就会从调用堆栈中删除。
第2步:处理微任务队列
- 调用堆栈为空后,事件循环会检查微任务队列。
- 它从微任务队列获取第一条消息并将其推送到调用堆栈来执行。
- 该函数运行,一旦完成,就会从调用堆栈中删除。
- 事件循环然后移动到微任务队列中的下一条消息并重复该过程。
- 这会一直持续到微任务队列中不再有消息为止。
第三步:处理任务队列
- 一旦调用堆栈和微任务队列都为空,事件循环就会转向任务队列。
- 它选择任务队列中的第一条消息并将其添加到调用堆栈。
- 函数运行,完成后,它会从调用堆栈中删除。
- 事件循环将对任务队列中的每个任务继续此过程,确保所有任务都被一一处理。
按照这个顺序——调用堆栈,然后微任务队列,最后任务队列——事件循环帮助JavaScript有效地处理异步代码,即使在它的单线程环境。
示例
现在我们了解了事件循环的工作原理以及任务的优先级如何确定,让我们看一些示例。
实施例1
const a = new Promise(function showA(resolve){ console.log('A'); resolve('B'); }); setTimeout(function showC() { console.log('C'); }, 0); a.then(function showB(b) { console.log(b); }); const d = function showD() { console.log('D'); }; d();
在继续之前,尝试考虑一下输出的顺序。
✨你期望它是什么?✨
让我们分解代码的每个部分来理解为什么我们会得到这个输出。
1。创造承诺
const a = new Promise(function showA(resolve) { console.log('A'); resolve('B'); });
- 在这里,我们创建一个带有回调函数的新 Promise。
- 在此函数内,console.log('A') 会立即执行,因此 "A" 会打印到控制台。
- 记录“A”后,promise 被解析为值“B”。
- JavaScript 识别出有一个 .then 回调(即 showB),一旦主调用堆栈清除,该回调应该运行,因此它将 showB 添加到 微任务队列(因为 Promise 解析会去那里)。
2。 setTimeout 调用
setTimeout(function showC() { console.log('C'); }, 0);
- setTimeout 函数安排 showC 在 0 毫秒后运行。
- JavaScript 将 showC 放入任务队列中,因为它是一个基于计时器的函数。
3。 a.then 回调
const a = new Promise(function showA(resolve){ console.log('A'); resolve('B'); }); setTimeout(function showC() { console.log('C'); }, 0); a.then(function showB(b) { console.log(b); }); const d = function showD() { console.log('D'); }; d();
- 这一行为我们在上一步中已经解决的 Promise 注册了一个 .then 处理程序 (resolve('B'))。
- 由于 Promise 已解决,showB(.then 回调)被添加到 微任务队列。
4。定义 d
const a = new Promise(function showA(resolve) { console.log('A'); resolve('B'); });
- 这一行只是定义了函数 showD 但尚未执行它,所以这里什么也没有发生。
5。调用 d()
setTimeout(function showC() { console.log('C'); }, 0);
- 现在,我们调用 d(),它被添加到 调用堆栈 并执行。 这会产生 console.log('D'),因此 "D" 会打印到控制台。
最终输出顺序:
a.then(function showB(b) { console.log(b); });
GIF供参考
互动示例
实施例2
const d = function showD() { console.log('D'); };
再次花点时间考虑一下输出的顺序。
✨你期望它是什么?✨
让我们来解释一下......
1。记录“开始!”
d();
- 这行代码被添加到调用堆栈并立即执行。
- 结果,“开始!” 被打印到控制台。
- 设置超时调用
A D B C
- setTimeout 函数安排 showTimeout 在 0 毫秒后运行。
- JavaScript 将 showTimeout 放置在 任务队列 中,因为它是一个基于计时器的函数。
3。承诺决议
console.log("Start!"); setTimeout(function showTimeout() { console.log("Timeout!"); }, 0); Promise.resolve("Promise!") .then(function showPromise(res) { console.log(res); }); console.log("End!");
- 承诺立即得到解决,值为“Promise!”。
- JavaScript 将 showPromise(.then 回调)放入 微任务队列,因为 Promise 在解析后会进入微任务队列。
4。记录“结束!”
console.log("Start!");
- 这行代码被添加到调用堆栈并立即执行。
- 结果,“结束!” 被打印到控制台。
最终输出顺序:
setTimeout(function showTimeout() { console.log("Timeout!"); }, 0);
GIF供参考
互动示例
结尾
本章并不太长,但我希望这些示例可以帮助您理解事件循环的工作原理。
我强烈建议尝试交互式页面来分析其他示例。在该页面上进行操作可以更轻松地理解正在运行的事件循环。
非常感谢大家对我之前帖子的喜爱!
下周见! ?
再见
以上是技术面试问题 - 部分事件循环的详细内容。更多信息请关注PHP中文网其他相关文章!

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

SublimeText3 Linux新版
SublimeText3 Linux最新版