JavaScript 是如何工作的?🤔
您是否知道 JavaScript 的简单语句在背后需要做很多工作才能执行?
嗯……
所以浏览器不能直接理解 JavaScript。
那么我们该如何让浏览器执行某些操作呢?
我们先来了解一下浏览器能理解什么语言。
浏览器只理解 0 和 1 组成的语言,也就是二进制/位格式的语句。
我们无法轻松地将整个 JavaScript 代码转换成字节流。那么现在该怎么办呢?🤔
JavaScript 引擎: “嘿,别担心,我可以帮助你,把你的 JavaScript 文件给我”。
那么 JavaScript 引擎是什么?
当 JavaScript 文件加载到浏览器中时,JavaScript 引擎会从上到下逐行执行该文件(异步代码除外,我们将在本系列的后续部分讨论异步)。JavaScript
引擎将逐行解析代码,并将其转换为机器码(二进制/位格式)。
现在浏览器可以理解该机器代码并相应地执行操作。
以下是一些 JS 引擎示例。
更正:-
随着 Edge 79 的发布,微软正在转向使用 V8 JavaScript 引擎的 Blink 浏览器引擎。
Blink 和 V8 均基于 Chromium 开发。Chromium 是一个开源项目,其开源网络浏览器也与其同名。谷歌的 Chrome 浏览器也使用了 Chromium 这个开源浏览器。现在,微软的 Chromium Edge 也将沿用 Chromium 的架构。
那么这个 javascript 引擎里面有什么?
这是 JavaScript 引擎的一个非常基本的视图。
内存堆
JavaScript 引擎有时无法在编译时分配内存,因此在运行时分配的变量会被放入内存堆(非结构化的内存区域)。
即使在退出在堆中分配内存的函数后,我们在堆中分配的数据/对象仍然存在。
这里我们面临一个主要的内存泄漏问题。
那么什么是内存泄漏?
内存堆的空间是有限的。
如果我们一直使用堆空间而不关心释放未使用的内存,当堆内没有更多可用内存时,就会导致内存泄漏问题。
为了解决这个问题,javascript 引擎引入了垃圾收集器。
什么是垃圾收集器?
垃圾回收是一种内存管理方式。它就像一个收集器,试图释放那些不再使用的对象所占用的内存。换句话说,当一个变量失去所有引用时,垃圾回收会将该内存标记为“不可达”并释放它。
执行上下文堆栈
堆栈是一种遵循后进先出 (LIFO)原则的数据结构(最后进入堆栈的项目将是第一个从堆栈中移除的项目)。
ECS 存储所有函数的执行上下文。执行上下文被定义为存储局部变量、函数和对象的对象。
简单来说,每个函数都被压在栈顶。JavaScript
引擎会执行位于栈顶的函数。
由于 JavaScript 引擎只有一个 ECS,因此它一次只能执行 ECS 顶部的一项任务。这就是 JavaScript 单线程的原因。
您一定听说过 Stack Overflow。
这是什么意思? ECS 的空间也是有限的。所以,如果我们不断地在栈顶添加函数,到某个时候,就没有足够的空间来添加更多的栈帧了。这时,就会出现栈溢出错误。
考虑以下示例。
function heyJS() {
console.log("Hello you are awesome!!!!");
heyJS();
}
heyJS();
好吧,这进入了无限递归,并且出现了堆栈溢出错误。
正如我提到的,JavaScript 是一种简单的线程语言,这意味着它只有一个调用堆栈,因此它一次只能执行一个语句。
等等,我们还听说过 JavaScript 中的异步编程。
那么,当一次只允许执行一个任务时,它是如何工作的呢?
这里是Web API和回调队列。
Web API
Web API 不是 JS 引擎的一部分,而是浏览器提供的 JavaScript 运行时环境的一部分。JavaScript 只是为我们提供了一种访问这些 API 的机制。由于 Web API 是特定于浏览器的,因此它们可能因浏览器而异。在某些情况下,某些 Web API 可能在一个浏览器中存在,而在另一个浏览器中不存在。
例子:
document.getElementById();
document.addEventListerner();
setTimeOut();
setInterval();
例子:-
console.log(“First!”);
setTimeout(() => {
console.log(“Second!”);
}, 1000 );
console.log(“Third!”);
/*
OutPut:-
First
Third
Second
*/
这很奇怪吧?
“Second” 在 setTimeout 里面,所以会在 1 秒后执行。
幕后究竟发生了什么?
1 秒后,WebAPI 会收到通知,告诉你,你现在需要执行一些代码。WebAPI
说:“哦,是 console.log(),我需要执行它,但我不能直接执行。我们把它发送到回调队列吧。”
“嘿,队列里有回调,请把它添加到你的列表中并执行它。”
回调队列
回调队列或消息队列是一种遵循先进先出原则的队列数据结构(先插入队列的项目将先从队列中移除)。它存储所有从事件表移动到事件队列的消息。每条消息都有一个关联的函数。回调队列维护消息或方法在队列中添加的顺序。
事件循环
事件循环不断检查执行上下文堆栈是否为空,以及事件队列中是否有任何消息。只有当执行上下文堆栈为空时,它才会将方法从回调队列移动到 ECS。
回调队列
“嘿,事件循环请检查 ECS 是否为空。我有一些回调需要推送到 ECS。”
事件循环
“队列请给我回调ECS现在是空的,我会将它们推送到堆栈上以执行它们。”
最后,我们将得到输出。
// First
// Third
// Second
这只是 JavaScript 引擎工作原理的概述。
JavaScript 引擎比我们今天讨论的要复杂得多。
我将尝试在未来的一些文章中更深入地探讨 JavaScript 引擎。
在本系列的下一篇文章中,我将解释 Javascript 类型、值和变量。
希望你喜欢它,如果喜欢的话请**喜欢并分享**。
感谢您的时间。
编码愉快……
文章来源:https://dev.to/ganeshjaiwal/how-does-javascript-work-45oc