无 DOM、静态类型、提前编译的 JavaScript 代码与本机代码的性能相比如何?

Hel*_*rld 5 javascript performance jit native compilation

“为什么 Javascript 比本机代码慢?”的传统答案 是:“因为它被解释了”。这种说法的问题在于解释并不是语言本身的品质。事实上,现在大多数 Javascript 代码都经过 JIT 处理,但这还远未接近本机速度。

如果我们从方程中删除解释因素并编译 Javascript AOT 会怎么样?它会与本机代码的性能相匹配吗?如果是,为什么这没有通过网络广泛完成*?如果不是,那么现在的性能瓶颈在哪里?

如果新的瓶颈是 DOM,如果我们也消除它会怎么样?一个无 DOM 的、已编译的 Javascript 会和本机代码一样高效吗?如果是,为什么这没有通过网络广泛完成**?如果不是,那么现在的性能瓶颈在哪里?

在剥离 DOM 部分和解释部分之后,我能看到 Javascript 和 C/C++ 之间唯一的大区别是前者具有动态类型。假设我们也消除了这一点,最终得到一个无 DOM、静态类型、提前编译的 Javascipt。与本机代码相比如何?如果它同样有效,为什么没有广泛使用呢?如果没有的话,现在的瓶颈在哪里?在这种情况下,JavaScript 几乎与 C 相同。

*有人可能会说 JIT 加载速度更快,但这并不能解释为什么 AOT 没有用于资源密集型 Web 应用程序(例如 3D 视频游戏),在这些应用程序中,AOT 性能优势非常值得最初的 AOT 编译延迟。(无论如何,都会出现明显的“游戏加载”延迟)

**无 DOM 的 javascript 将使用 WebGL/Canvas 与用户交互。目前这需要最少的 DOM,它定义了最初的 HTML5 Canvas,但理论上如果值得性能优势的话,可以通过修改技术来消除这种情况。假设回答时可以使用 DOM-less WebGL/Canvas。

编辑:我说的是客户端编译。

小智 5

事实上,回答你的问题,是的。或者说是这样。当然,如果有适当的编译器,您可以提前编译任何内容。

确实,Javascript 的 AOT 编译是一个有点奇怪的概念。AOT 编译和“一次编写,随处运行”是一个矛盾,因为通过编译它,您是在说,“我希望它在这个特定的 CPU 上运行”。

不过,也有一些尝试。看一下 asm.js。您编写 C 程序,然后通过一些步骤将其转换为 Javascript 模块。然后,该模块由 Firefox 加载,并且由于它以某种方式标记(ams="true" 或其他),浏览器会尝试提前编译它。结果几乎是本机速度。然而,代码可以尝试执行的操作有很多限制(几乎是您上面引用的所有限制),除了算法之外,我看不到它的许多用例。

话虽如此,我觉得其他贡献者的回答过于严厉,因为你触及的是人们实际上正在尝试做的事情。


Eli*_*gem 0

重要提示:
您似乎提倡使用剥离的、静态类型的可编译版本的 JS。首先表明的是你不知道 JS 是什么:一种多范式编程语言,支持基于原型的 OO、命令式和函数式编程范式。关键是功能范式。除了 Haskell(在定义了自己的中缀运算符后可以进行某种强类型化)之外,函数式语言不能是静态类型化的(AFAIK)。想象一下类似 C 的函数定义返回闭包:

function a = (function (Object g)
{
    char[] closureChar = g.location.href;
    Object foo = {};
    Function foo.bar = char* function()
    {//This is a right mess
        return &closureChar;
    };
}(this));
Run Code Online (Sandbox Code Playgroud)

函数也是第一类对象。使用大量返回对象的 lamda 函数、可能返回自身的引用函数、其他函数、对象或基元......你到底要如何编写所有这些?Js 函数既是创建作用域、构建代码、控制程序流程的一种方式,也可以是分配给变量的东西。

提前编译 JS 的问题非常简单:编译的代码必须在如此众多的不同平台上运行:运行 Windows、OSX、linux、UNIX 的台式机/笔记本电脑以及具有不同功能的平板电脑和智能手机。移动浏览器...
即使你确实编写和编译了在所有平台上运行的 JS,JS 的速度仍然受限于它是单线程的,并且运行在 JS 引擎上(就像 Java 运行在虚拟机上一样)。

客户端代码的编译已经完成。确实,这需要一些时间,但不是很多。它非常消耗资源,因此大多数现代浏览器都会以已经完成大量预处理的方式缓存代码。始终可以编译的内容也将以其编译状态进行缓存。V8 是一个开源、快速的 JS 引擎。如果需要,您可以检查源代码,了解如何确定 JS 代码的哪些方面已编译,哪些未编译。
即便如此,这只是 V8 的工作原理……JS 引擎与代码运行速度有更多关系:有些非常快,有些则不然。有些人在某件事上速度更快,而另一些人则在另一领域胜过所有竞争对手。更多详细信息可以在这里阅读

剥离 DOM 部分,并没有从语言中剥离任何东西。DOM API不是 JS 本身的一部分。JS 是一种表达能力很强的语言,但其核心是小型语言,就像 C 一样。两者都没有留给自己设备的 IO 功能,也无法解析 DOM。为此,JS 的浏览器实现可以访问 DOMParser 对象。
您建议使用最小的 DOM...嘿,每个有理智的人都支持改进的 DOM API。这远非网络上最好的事情。但你必须意识到 DOM 和 JS 是独立的实体。DOM(和 DOM API)由 W3 管理,而 ECMA 负责 JS。彼此之间都没有任何关系。这就是为什么 DOM 不能从 JS 中“剥离”的原因:它从一开始就不是 JS 的一部分。

既然你将 JS 与 C++ 进行比较:你可以编写可以在 Windows 和 Linux 机器上编译的 C++ 代码,但这并不像听起来那么容易。但既然你自己提到了 C++,我想你可能也知道这一点。
说到这里,如果您看到 C++ 和 JS 之间唯一真正的区别是静态类型与动态类型,那么您确实应该花更多时间学习 JS。

虽然它的语法类似于 C,但该语言本身与 Lisp(即函数式编程)有更多相似之处。它不知道这样的类,但使用原型......老实说,动态类型确实没什么大不了的。

所以,底线是:
编译 JS 以在每台机器上运行将导致类似于 MS 的 .NET 框架。其背后的理念是:“编写一次,到处运行” ……事实证明这根本不是真的。
JavaX 平台,但这只是因为它没有编译为本机代码,而是在虚拟机上运行。
最后,ECMAScript 标准(JS 是其最常见的实现)并不是那么好,它是该领域所有主要竞争对手共同努力的结果:Mozilla、Google、微软和一些无关的瑞士公司。这是一个巨大的妥协。想象一下这三个大人物同意一起为 JS 开发一个编译器。Microsoft 将推出最好的JScript 编译器,Google 将有自己的想法,而 Mozilla 可能会根据社区的需求准备 3 种不同的编译器。

编辑:
您进行了编辑,澄清您正在谈论客户端 JS。因为您觉得有必要指定这一点,所以我觉得您似乎并不完全确定 JS 在哪里结束,以及浏览器在哪里接管。
JS 被设计为一种非常可移植的语言:它没有 IO 功能,支持多种开发范例,并且(最初)是一种完全解释型语言。确实,它是在考虑到 Web 的情况下开发的,但您可以(而且有些人确实这样做)使用这种语言来查询数据库 (MongoDB),作为替代批处理脚本语言 (JScript) 或服务器端脚本语言(backbone、节点.js,...)。有些使用 ECMAScript(JS 的基本标准)来制作自己的编程语言(是的,我说的是 Flash ActionScript)。

根据用例,JS 将有权访问非该语言本机的对象/API(document[Object http].createServer[Object file].readFileSync分别用于 DOM 访问、Web 服务器功能和 IO)。这些往往构成瓶颈,而不是语言本身。

正如我所暗示的,JS最初是一种解释性语言。老实说,正如当今的情况一样,编译语言和解释语言之间的区别在过去十年中已经逐渐消失。
C/C++ 曾经是严格编译的语言,但在某些情况下 (.NET) C++ 代码不再需要编译为机器代码......
同时,像 Python 这样的脚本语言有很多用途,它们“通常将其视为一种编程语言,因为脚本语言一词在某种程度上意味着“较小的语言”
几年前,随着 PHP5 的发布,ZendEngine2 也随之发布。从此,PHP被编译为字节码并在虚拟机上运行。您可以使用 APC 缓存字节码。bcompiler 允许您从 PHP 代码生成独立的可执行文件,就像 Facebook 的 HPHPc(已弃用)用于将 PHP 编译为 C++,然后编译为本机代码一样。现在,facebook 使用 HHVM,这是一个定制的虚拟机。在这里了解更多信息

在 JavaScript 解释器(现在称为引擎)中也可以看到同样的演变。它们不是您日常的旧的解析和执行线程,正如您似乎仍然认为的那样。在内存管理、JITCompilation(甚至是尾部堆栈优化)、优化以及其他方面,有很多神奇的事情发生......
所有伟大的事情,但这些使得很难确定实际的瓶颈在哪里。每个引擎优化方式的差异甚至超过 IE6 与 IE10 的差异,因此几乎不可能明确找出瓶颈。如果一个浏览器需要 10 秒来完成 DOM 密集型任务,则另一个浏览器可能只需要 1~2 秒。然而,如果相同的浏览器相互竞争来检查 RegExp 对象的性能,那么情况可能会有所不同。
我们不要忘记,在您写完有关您的发现的博客文章后,您必须检查这两个浏览器是否都没有发布声称可以加快某些任务速度的新版本/更新。