摘要:调用栈是一种单线程编程语言,这意味着它只有一个调用堆栈。调用栈是一种数据结构,它记录了我们在程序中的位置。而且这不是唯一的问题,一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。
本文是旨在深入研究JavaScript及其实际工作原理的系列文章中的第一篇:我们认为通过了解JavaScript的构建块以及它们是如何工作的,将能够编写更好的代码和应用程序。我们还将分享构建 SeStHealsStad 时使用的一些经验法则,这是一个轻量级的 JavaScript 应用程序,必须保持健壮和高性能以保持竞争力。
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!
如 GitHut 统计 数据所示,在GitHub中的活动存储库和总推送方面,JavaScript处于顶部。它也不落后于其他类别。
如果项目越来越依赖于 JavaScript,这意味着开发人员必须利用语言和生态系统提供的所有内容,对内部进行更深入的了解,以便构建出色的软件。
事实证明,有很多开发人员每天都在使用JavaScript,但却不知道背后发生了什么。
概述几乎每个人都已经听说过 V8 引擎,大多数人都知道 JavaScript 是单线程的,或者它使用的是回调队列。
在本文中,我们将详细介绍这些概念,并解释 JavaScrip 实际如何运行。通过了解这些细节,你将能够适当地利用所提供的 API 来编写更好的、非阻塞的应用程序。
如果您对JavaScript还比较陌生,那么本文将帮助您理解为什么JavaScript与其他语言相比如此“怪异”。
如果你是一个有经验的JavaScript开发人员,希望它能让您对每天使用的JavaScript运行时的实际工作方式有一些新的见解。
JavaScript引擎JavaScript引擎的一个流行示例是Google的V8引擎。例如,在Chrome和Node.js中使用V8引擎,下面是一个非常简化的视图:
V8引擎由两个主要部件组成:
emory Heap(内存堆) — 内存分配地址的地方
Call Stack(调用堆栈) — 代码执行的地方
Runtime(运行时)有些浏览器的 API 经常被使用到(比如说:setTimeout),但是,这些 API 却不是引擎提供的。那么,他们是从哪儿来的呢?事实上这里面实际情况有点复杂。
所以说我们还有很多引擎之外的 API,我们把这些称为浏览器提供 API 称为 Web API,比如说 DOM、AJAX、setTimeout等等。
然后我们还拥有如此流行的事件循环和回调队列。
调用栈JavaScript是一种单线程编程语言,这意味着它只有一个调用堆栈。因此,它一次只能做一件事。
调用栈是一种数据结构,它记录了我们在程序中的位置。如果我们运行到一个函数,它就会将其放置到栈顶,当从这个函数返回的时候,就会将这个函数从栈顶弹出,这就是调用栈做的事情。
来个栗子:
当程序开始执行的时候,调用栈是空的,然后,步骤如下:
每一个进入调用栈的都称为调用帧。
这能清楚的知道当异常发生的时候堆栈追踪是怎么被构造的,堆栈的状态是如何的,让我们看一下下面的代码:
如果这发生在 Chrome 里(假设这段代码实在一个名为 foo.js 的文件中),那么将会生成以下的堆栈追踪:
"堆栈溢出",当你达到调用栈最大的大小的时候就会发生这种情况,而且这相当容易发生,特别是在你写递归的时候却没有全方位的测试它。我们来看看下面的代码:
当引擎开始执行这段代码时,它首先调用函数“foo”。然而,这个函数是递归的,并且在没有任何终止条件的情况下开始调用自己。因此,在执行的每一步中,相同的函数都会被一次又一次地添加到调用堆栈中,如下所示:
然而,在某些时候,调用堆栈中的函数调用数量超过了调用堆栈的实际大小,浏览器决定采取行动,抛出一个错误,它可能是这样的:
在单个线程上运行代码很容易,因为你不必处理在多线程环境中出现的复杂场景——例如死锁。
但是在一个线程上运行也非常有限制,由于 JavaScript 只有一个调用堆栈,当某段代码运行变慢时会发生什么?
当调用堆栈中的函数调用需要花费大量时间来处理时会发生什么情况? 例如,假设你希望在浏览器中使用JavaScript进行一些复杂的图像转换。
你可能会问-为什么这是一个问题?问题是,当调用堆栈有函数要执行时,浏览器实际上不能做任何其他事情——它被阻塞了,这意味着浏览器不能呈现,它不能运行任何其他代码,它只是卡住了,如果你想在应用中使用流畅的页面效果,这就会产生问题。
而且这不是唯一的问题,一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。大多数浏览器都会这么做,报一个错误,询问你是否想终止 web 页面。
这并不是最好的用户体验,不是吗?
那么,我们怎样才能在不阻塞UI和不使浏览器失去响应的情况下执行大量代码呢?解决方案是异步回调。
这个在下一篇说明,我尽快把原作者的内容整理好!
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://blog.sessionstack.com...
你的点赞是我持续分享好东西的动力,欢迎点赞!
交流干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,即可看到福利,你懂的。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/99968.html
摘要:如果我们进入一个函数,我们在堆栈的顶部。看看下面的代码当引擎开始执行此代码时,调用堆栈将为空。之后,步骤如下调用堆栈中的每个条目称为堆栈帧。这正是抛出异常时构造堆栈跟踪的方式当异常发生时,它基本上是调用堆栈的状态。 随着JavaScript越来越受欢迎,团队正在利用这个技术栈在多个层次- 前端,后端,混合应用程序,嵌入式设备等等提供支持。 这篇文章旨在成为系列中第一个旨在深入挖掘Jav...
摘要:为了方便大家共同学习,整理了之前博客系列的文章,目前已整理是如何工作这个系列,可以请猛戳博客查看。以下列出该系列目录,欢迎点个星星,我将更友动力整理理优质的文章,一起学习。 为了方便大家共同学习,整理了之前博客系列的文章,目前已整理 JavaScript 是如何工作这个系列,可以请猛戳GitHub博客查看。 以下列出该系列目录,欢迎点个星星,我将更友动力整理理优质的文章,一起学习。 J...
摘要:调用堆栈是存放原始数据类型的地方除了函数调用之外。上一节中声明变量后调用堆栈的粗略表示如下。解释改变的正确方法是更改内存地址。在声明时,将在调用堆栈上分配内存地址,该值是在堆上分配的内存地址。 这是专门探索 JavaScript 及其所构建的组件的系列文章的第 21 篇。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 如果你错过了前面的章节,可以在这里找到它们:...
摘要:无论你使用的是解释型语言还是编译型语言,都有一个共同的部分将源代码作为纯文本解析为抽象语法树的数据结构。和抽象语法树相对的是具体语法树,通常称作分析树。这是引入字节码缓存的原因。 这是专门探索 JavaScript 及其所构建的组件的系列文章的第 14 篇。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 如果你错过了前面的章节,可以在这里找到它们: JavaS...
摘要:调用栈是一种数据结构,它记录了我们在程序中的位置。当从这个函数返回的时候,就会将这个函数从栈顶弹出,这就是调用栈做的事情。而且这不是唯一的问题,一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。 原文地址: https://blog.sessionstack.com... PS: 好久没写东西了,最近一直在准备写一个自己的博客,最后一些技术方向已经敲定了,又可以...
阅读 3153·2021-11-22 14:45
阅读 3299·2019-08-29 13:11
阅读 2305·2019-08-29 12:31
阅读 921·2019-08-29 11:21
阅读 2990·2019-08-29 11:09
阅读 3615·2019-08-28 18:11
阅读 1419·2019-08-26 13:58
阅读 1272·2019-08-26 13:27