JavaScript是如何工作的:引擎,运行时以及调用栈的概述

原文:How JavaScript works: an overview of the engine, the runtime, and the call stack

译者:neal1991

welcome to star my articles-translator, providing you advanced articles translation. Any suggestion, please issue or contact me

LICENSE: MIT

随着JavaScript变得越来越流行,团队在多个层级都对它进行利用-前端,后端,混合应用,嵌入式设备以及更多。

正如GitHut stats所展示的那样,JavaScript是Github上面最活跃以及总Push次数最多的语言。在其它类别中也不会落后太多。

(获取最新的 GitHub language stats).

如果项目对于JavaScript越来越依赖,这意味着为了构建好的软件开发者必须利用这个JS提供的一切并且对于生态系统的内部有着更深的理解。

因此,尽管每天有很多开发者在使用JavaScript,但并不知道内部到底发生了什么。

概览

几乎每个人都已经听说过V8引擎的概念,并且很多知道JavaScript是单线程的或者它是使用一个回调队列的。

在这篇博文中,我们将会详细讲述所有概念并且解释JavaScript是如何真正运行的。在了解这些细节之后,你将能够写出能够适宜地利用提供的API的更好的,非阻塞的app。

如果对于JvaScript来说还不是很了解,这篇博文将会帮助你理解为什么JavaScript和别的语言相比如此“奇怪”。

如果你是一个有经验的JavaScript开发者,希望这篇文章能够让你对你每天使用的JavaScript Runtime是如何真正工作的。

JavaScript 引擎

最流行的JavaScript引擎的例子之一就是谷歌的V8引擎。比如Chrome以及Node.js内部就是使用V8引擎。下面是一个简单的视图示例:

引擎主要由两个部分组成:

  • 内存堆——这是内存分配发生的地方
  • 回调——这是你代码执行时的栈帧。

Runtime

有很多浏览器中的API几乎都被JavaScript开发者使用过(比如:’setTimeout’)。然而这些API并不是由引擎提供的。

那么,它们是从哪来的呢?

事实证明这有一点复杂。

因此,虽然我们有引擎但实际上是有更多。我们有那些由浏览器提供的Web API,像DOM, AJAX, setTimeout以及更多。

接着,我们还有非常流行的事件循环(event loo)以及回调队列(callback queue)

调用栈

JavaScript是一种单线程的编程语言,这意味着它只拥有一个单独的调用栈。因此它一次只能做一件事情。

调用栈是一种数据结构记录着我们正在程序的什么地方。如果我们步入一个函数,我们就将这个函数放在栈的顶部。如果我们从一个函数返回,我们则是将这个函数从栈顶弹出。这就是这个栈所做的一切。

让我们看一个例子。参看如下代码:

function multiply(x, y) {
return x * y;
} function printSquare(x) {
var s = multiply(x, x);
console.log(s);
} printSquare(5);

当引擎执行这段代码的时候,调用栈首先将会是空的。然后,将会按照以下步骤进行:

调用栈中的每一项都被称为栈帧(Stack Frame)

并且这正是都异常被抛出的时候栈追踪是如何构建的——这基本就是异常发生时调用栈的状态。请看如下代码:

function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
} function bar() {
foo();
} function start() {
bar();
} start();

如果这段代码在Chrome中执行(假设代码是在一个叫做foo.js的文件中),接下来的栈追踪将会产生:

爆栈“——当你达到最大调用栈的大小的时候就会发生这种情况。并且这种情况很容易产生,特别是你没有对你的代码做全面的测试的时候。请看下面的示例代码:

function foo() {
foo();
} foo();

当引擎开始执行这段代码的时候,它一开始调用函数”foo“。然而,这个函数递归调用本身并且没有终止条件。因此在每一个执行的步骤中,相同的函数都会一次又一次地被添加到调用栈中。看起来就像这样:

在某个点,然而函数调用的数量就超过调用栈的实际尺寸,那么浏览器就决定采取行动,抛出一个错误,看起来是这个样子的:

在单线程环境中运行代码可能相当容易因为你不需要处理多线程环境中复杂的情形——比如,死锁。

但是在单线程环境中也可能遇到种种限制。因为JavaScript具有一个单独的调用栈,当事情变得缓慢的时候到底发生了什么?

并发以及事件循环

当你的函数调用在调用栈中花了大量的时间来进行到底发生了什么?比如,想象一下假如你想在浏览器中使用JavaScript来做一些复杂的图像转换。

你可能会问——为什么这也会是一个问题?问题是尽管调用栈具有函数来执行,但是浏览器实施中不能做任何其他的事——它被阻塞了。这意味着浏览器不能渲染,它不能运行其他的代码,它就是歇菜了。如果你希望你的app能够具有流畅的UI的时候就会产生问题。

并且这不是唯一的问题。一旦你的浏览器开始处理调用栈中的大量任务,他将在很长时间内都无法响应。大多数浏览器通过抛出错误来采取行动,询问你是否想中止网页。

现在,这并不是一种最好的用户体验,是不是?

因此,我们如何在不阻塞UI并且让浏览器保持响应的情况下执行大量的代码?解决方案就是异步回调

这个将会在”JavaScript是如何工作的”的第二部分进一步解释。

同时,如果你很难在你的JavaScript重现并且理解问题的时候,可以看看 SessionStack。SessionStack记录了你的web应用中的一切:所有的DOM变化,用户交互,JavaScript异常,栈追踪,失败的网络请求以及调试消息。

使用SessionStack,你可以重现你的web应用中的问题就像录像一样,并且可以看到用户交互的一切。

现在有一个免费的计划能够允许你可以开始免费试用

可以扫描二维码或者搜索 mad_coder 关注微信公众号,点击阅读原文可以获取链接版原文。

JavaScript是如何工作的:引擎,运行时间以及调用栈的概述的更多相关文章

  1. JavaScript是如何工作的:引擎,运行时和调用堆栈的概述!

    摘要: 理解JS执行原理. 原文:JavaScript是如何工作的:引擎,运行时和调用堆栈的概述! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 本文是旨在深入研究JavaScrip ...

  2. JavaScript是如何工作的01:引擎,运行时和调用堆栈的概述!

    概述 几乎每个人都已经听说过 V8 引擎,大多数人都知道 JavaScript 是单线程的,或者它使用的是回调队列. 在本文中,我们将详细介绍这些概念,并解释 JavaScrip 实际如何运行.通过了 ...

  3. 浏览器-09 javascript引擎和Chromium网络栈

    语言的运行 C/C++语言 使用编译器直接将它们编译成本地代码(机器指令),这是由开发人员在代码编写完成之后实施; 用户只是使用这些编译好的本地代码,这些本地代码被系统的加载器加载执行,由操作系统调度 ...

  4. JavaScript 是如何工作的:JavaScript 的共享传递和按值传递

    摘要: 原始数据类型和引用数据类型的副本作为参数传递给函数. 原文:JavaScript 是如何工作的:JavaScript 的共享传递和按值传递 作者:前端小智 Fundebug经授权转载,版权归原 ...

  5. JavaScript 是如何工作的:JavaScript 的内存模型

    摘要: 从内存角度理解 let 和 const 的意义. 原文:JavaScript 是如何工作的:JavaScript 的内存模型 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这 ...

  6. JavaScript是如何工作的:编写自己的Web开发框架 + React及其虚拟DOM原理

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 19 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  7. JavaScript 是如何工作:Shadow DOM 的内部结构 + 如何编写独立的组件!

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 17 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  8. JavaScript是如何工作的:深入类和继承内部原理 + Babel和TypeScript 之间转换

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 15 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  9. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

随机推荐

  1. 模板_SEG_TREE

    #include<bits/stdc++.h> #define maxn 500005 #define int long long using namespace std; inline ...

  2. smooth L1损失函数

    当预测值与目标值相差很大时,L2 Loss的梯度为(x-t),容易产生梯度爆炸,L1 Loss的梯度为常数,通过使用Smooth L1 Loss,在预测值与目标值相差较大时,由L2 Loss转为L1  ...

  3. Mac 安装 MongoDB 数据库

    1. 使用 brew install mongodb 安装 (参见下图) 2. 安装成功如下图 (成功与否可参考 方框内字符) 3. 启动 MongoDB 数据库 3.1 先创建数据库存储目录 /da ...

  4. AttributeError: module 'datetime' has no attribute 'now'

    在用时间转化时,一直报AttributeError: module 'datetime' has no attribute 'now', 我用的 import datetime   datetime ...

  5. 搭建私有git仓库gogs

    安装 gogs 下载 gogs download 安装 解压压缩包. 使用命令 cd 进入到刚刚创建的目录. 执行命令 ./gogs web,然后,就没有然后了. #后台运行 $ nohup ./go ...

  6. 【转】Tarjan算法 资料合集

    http://blog.csdn.net/fuyukai/article/details/51039788 Tarjan三大算法之双连通分量(割点,桥) Robert Endre Tarjan是一个美 ...

  7. spring cloud:服务网关 Spring Cloud GateWay 入门

    Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gateway ,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?Zuul(1.x) 基于 Servlet,使 ...

  8. 每日踩坑 2019-07-30 H5 使用 iframe 底部有白边

    用个iframe累死累活的 用 js 动态计算高度, 结果明明px都对,然后却把页面滚动条也整出来了. 查看元素盒模型也一切正常. 然后仔细观察就发现是下边多了几个像素的白色边. 然后就 百度呗 以下 ...

  9. Ansible安装及常用模块

    配置文件:/etc/ansible/ansible.cfg 主机列表:/etc/ansible/hosts  安装anslibe  wget -O /etc/yum.repos.d/epel.repo ...

  10. p1848 [USACO12OPEN]书架Bookshelf

    分析 单调队列优化dp即可 正确性显然,详见代码 代码 #include<bits/stdc++.h> using namespace std; #define int long long ...