随着JavaScript的日益普及,越来越多的团队将JavaScript广泛应用于前端、后端、混合应用、嵌入式等领域。
本文旨在深入研究JavaScript,并解释JavaScript是如何工作的。通过了解它的底层结构和工作原理,我们可以帮助我们编写更好的代码和应用程序。据GitHut统计,JavaScript在GitHub中长期占据主动存储库和总推送的榜首,在其他类别中也不会落后太多。
如果一个项目越来越依赖于JavaScript,这意味着开发人员必须使用这些语言和生态系统提供的更深层的核心内容来构建一个令人兴奋的应用程序。然而,事实证明,许多开发人员每天都在使用JavaScript,但他们不知道JavaScript在底层是如何工作的。
总结
几乎每个人都听说过V8引擎的概念,大多数人都知道JavaScript是单线程的,或者说它使用回调队列。在本文中,我们将详细介绍这些概念,并解释JavaScript是如何工作的。通过了解这些细节,您可以使用这些API来编写更好的非阻塞应用程序。如果你不熟悉JavaScript,这篇文章将帮助你理解为什么JavaScript与其他语言相比如此“怪异”。如果你是一个有经验的JavaScript开发人员,我希望它能给你带来一些新的见解,并解释JavaScript的运行时,尽管你可能每天都在使用它。
JavaScript引擎
最受欢迎的JavaScript引擎是谷歌的V8引擎,用于Chrome和Node。下面是一个简单的图表来说明它们之间的关系:
这台发动机主要由两部分组成:
内存堆:这是内存分配发生的地方。调用栈:这是你的代码执行的地方。运行时间
经常使用一些浏览器API(例如setTimeout),但是这些API不是由引擎提供的。那么,他们是从哪里来的?其实这里的实际情况有点复杂。
所以除了引擎之外,我们还有很多API,我们称之为浏览器提供的Web API,比如DOM、AJAX、setTimeout等等。
然后我们有这样一个流行的事件循环和回调队列。
调用栈
JavaScript是单线程语言,这意味着它只有一个调用栈,所以一次只能做一件事。
调用栈是一种数据结构,它记录了我们在程序中的位置。如果我们运行一个函数,它会把它放在栈顶。从这个函数返回时,它会从栈顶弹出,这就是调用栈的作用。
让我们看看下面的例子:
函数乘法(x,y) {返回x * y;}函数printSquare(x) { var s=乘法(x,x);console.log} print square(5);当程序开始执行时,调用栈是空的,然后步骤如下:
调用堆栈中的每个条目都被称为_ _ call frame _ _。
这可以清楚地知道堆栈跟踪是如何构造的,以及异常发生时堆栈的状态是什么。让我们看看下面的代码:
function foo() {抛出新的Error('SessionStack将帮助您解决崩溃:)');}功能栏(){ foo();}函数start(){ bar();} start();如果在Chrome中发生这种情况(假设这段代码实际上在一个名为foo.js的文件中),将生成以下堆栈跟踪:
“堆栈溢出”,当您达到调用堆栈的最大大小时会发生这种情况,而且这种情况很容易发生,尤其是当您编写递归而没有对其进行全方位测试时。让我们看看下面的代码:
function foo(){ foo();} foo();当我们的引擎开始执行这段代码时,它以foo函数开始。那么它就是一个递归函数,并在没有任何终止条件的情况下开始调用自己。因此,在每个步骤中,相同的函数被一次又一次地添加到调用堆栈中。然后看起来是这样的:
然后,在某个时候,调用堆栈中函数调用的数量超过了调用堆栈的实际大小,浏览器决定将其终止并抛出一个错误。它看起来像这个:
在单线程上运行代码很容易,因为您不必处理复杂的场景——,例如多线程环境中的死锁。但是在一个线程上运行也非常有限。由于JavaScript只有一个调用栈,当一段代码运行缓慢时会发生什么?
并发和事件周期
调用栈中的函数调用需要大量的时间来处理,那么会发生什么呢?例如,假设您想在浏览器中使用JavaScript代码转换一些复杂的图片。
你可能会问。这是什么问题?其实问题是当调用栈有函数要执行的时候,浏览器什么都做不了,就会被阻塞。这意味着浏览器无法呈现,无法运行其他代码,并且被卡住了。如果您想在应用程序中使UI流畅,这将会导致问题。
这不是唯一的问题。一旦您的浏览器开始处理调用堆栈中的许多任务,它可能会长时间停止响应。大多数浏览器都会这样做,报告错误并询问您是否要终止网页。
摘要
以上是边肖介绍的JavaScript对引擎、运行时和调用栈的一般理解。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!