【问题标题】:How would a DOM-less,statically typed, ahead-of-time-compiled javascript code compare to native code performance-wise?在性能方面与原生代码相比,无 DOM、静态类型、提前编译的 JavaScript 代码如何?
【发布时间】:2013-04-28 21:27:15
【问题描述】:

“为什么 Javascript 比本机代码慢?”的传统答案是:“因为它被解释了”。这种说法的问题在于解释不是语言本身的质量。事实上,现在大多数 Javascript 代码都在进行 JITed,但这甚至还没有接近原生速度。

如果我们从等式中删除解释因子并编译 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。

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

【问题讨论】:

  • 如果您在谈论客户端编译,那么您是否必须在 客户端请求您的页面之前将 JS 代码发送给客户端?大多数(如果不是所有)浏览器 JIT 编译它们可以编译的内容,并缓存该脚本。这归结为您所追求的...... JS 的编译是资源密集型的,但同样:不是主要瓶颈。那就是 DOM API,以及运行 JS 的引擎。正如我在回答中解释的那样,这两个方面都与 JS 本身无关
  • 我想澄清一下,我说的是客户端编译。
  • 我知道,我看到了编辑。我的观点是:大多数 JS 代码被请求一次,编译(JIT-Compiled)和缓存,如果你第二次需要它,有效地预编译代码。显然,这不是主要瓶颈。那些不能预编译的部分是DOM API(不是JS本身的一部分)和JS引擎。某些引擎的预编译方式与其他引擎不同(请查看我的答案中的第一个链接,我会在那里详细介绍)。 V8 是开源的,不过......如果你想改变一些事情,请成为我的客人......
  • 我们几乎同时写了前两个 cmets,我的不是对你的回应。如果 Javascript 已完全编译,则不需要 Javascript 引擎(几乎是 JITer+解释器),对吗?
  • 这篇文章有太多的误解,我什至不知道从哪里开始......

标签: javascript performance compilation native jit


【解决方案1】:

其实,回答你的问题,是的。或之类的。当然,只要有合适的编译器,你就可以提前编译任何东西。

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

但是有一些尝试。看看 asm.js。您编写您的 C 程序,然后通过一些箍将其转换为 Javascript 模块。然后这个模块由 Firefox 加载,因为它以某种方式(ams="true" 或其他东西)被标记,浏览器会尝试提前编译它。结果几乎是本机速度。但是,代码可以尝试做的事情有很多限制(几乎所有您在上面引用的那些),除了算法之外,我看不到它的许多用例。

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

【讨论】:

    【解决方案2】:

    重要提示:
    您似乎提倡剥离的、静态类型的 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));
    

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

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

    编译代码客户端已经完成。诚然,这需要一些时间,但不是很多。这是相当资源密集型的,因此大多数现代浏览器都会以已经完成大量预处理的方式缓存代码。总是可以编译的东西,也将被缓存在它们的编译状态中。 V8 是一个开源的、快速的 JS 引擎。如果需要,您可以查看源代码,了解如何确定 JS 代码的哪些方面已编译,哪些未编译。
    即便如此,这只是 V8 的工作方式...... JS 引擎与代码运行的速度有更多关系:有些非常快,有些则不然。有些人在一件事上速度更快,而另一些人在另一个领域的表现优于所有竞争对手。 More details can be read here

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

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

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

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

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

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

    正如我所暗示的,JS 最初是一种解释性语言。就像现在一样,编译语言和解释语言之间的分界线在过去十年中一直在消退,老实说。
    C/C++ 曾经是严格编译的语言,但在某些情况下 (.NET) C++ 代码不再需要编译为机器代码...
    同时,像 Python 这样的脚本语言被用于多种用途,它们通常被视为一种编程语言,因为术语 脚本语言 在某种程度上暗示了一种“次要语言” em>.
    几年前,随着 PHP5 的发布,ZendEngine2 也发布了。从那时起,PHP 被编译为字节码并在虚拟机上运行。您可以使用 APC 缓存字节码。 bcompiler 允许您从 PHP 代码生成独立的可执行文件,就像 Facebook 的 HPHPc(已弃用)用于将 PHP 编译为 C++,然后编译为本机代码一样。现在,facebook 使用 HHVM,这是一个自定义虚拟机。 Find out more here.

    在 JavaScript 解释器(现在称为引擎)中可以看到相同的演变。它们不是你每天解析和执行的旧线程,你似乎仍然认为它们是。在内存管理、JITCompilation (tail stack optimizing even)、优化以及你有什么方面,有很多魔法正在发生......
    所有伟大的事情,但这些使得很难确定实际的瓶颈在哪里。每个引擎优化的方式比IE6与IE10的差异还要大,因此几乎不可能确定瓶颈。如果一个浏览器需要 10 秒来完成一项 DOM 密集型任务,那么另一个浏览器可能只需要 1~2 秒。但是,如果相同的浏览器相互竞争以检查 RegExp 对象的性能,则启动可能会在另一只脚上。
    我们不要忘记,在您撰写有关您的发现的博客文章后,您必须检查是否没有任何浏览器发布声称可以加快某些任务的新版本/更新。

    【讨论】:

    • 感谢您的回答。瓶颈部分对我来说仍然有点不清楚。假设我们编译 DOM-less Javascript,它会比原生代码慢吗?瓶颈到底在哪里?
    • 我认为“一次编写,随处运行”非常适用于当前形式的 Javascript,我的意思是,几乎所有地方都运行相同的 Javascript 代码,不是吗(不包括浏览器的细微差异)?此外,.NET 使用字节码,而不是本机代码。
    • 瓶颈是否在于 Javascript 是一种动态语言这一事实​​?
    • @HelloWorld:瓶颈不在于 JS 作为一门语言本身,而在于引擎和 API。 DOM 不是 JS 的一部分,它是一个 API……将其与从 C 程序中访问 SQL 数据库进行比较,只有 API 缓慢、庞大且笨重。 .NET 使用字节码,是的,但微软希望促进移动开发(随着 W8 的发布),并声称每个应用程序只能编写一次,并且可以在台式机和平板电脑上运行。这部分今天仍然不正确。 JS 作为一种动态语言根本不是瓶颈。
    • 请解释否决票(无论是谁 DV)。我不介意,只要我能从中吸取教训,也可以
    【解决方案3】:

    我倾向于认为它会快很多,但它也限制了你可以轻松完成的事情,因为 DOM 实际上在某些事情上工作得很好。

    DOM 是为文档设计的;它的设计并没有真正考虑到 UI。也就是说,DOM 最困难的问题之一是使其与模型保持同步,因为 DOM 本质上是静态的,即使是最小的更改也会导致回流(这可能很慢)。 React 和其他虚拟 DOM 框架试图通过一次替换整个 DOM 并使用 VDOM 差异来最小化更改量来回避这一点。另一方面,使用画布让屏幕与模型保持同步变得非常简单,因为您可以使用新数据重新绘制画布并继续前进。

    将渲染移到画布上省去了中间人,让您可以进行自己的渲染、布局和样式设置。权衡是显而易见的。您现在必须手动管理所有事件处理和滚动,而且嵌入实际文档将是一场噩梦。如果某个框架要为此设计一个解决方案,它可能是一个没有 DOM 杂乱无章的可行的、高性能的替代方案,但这可能对新闻网站、博客、社交媒体或大多数文本繁重的网站没有意义.这类事情可能会为绘图应用程序、游戏甚至聊天应用程序带来巨大的性能提升,但不会有很多其他领域受益。或者他们会?我很高兴被证明是错误的。

    DOM 在很大程度上是一个方形钉子,我们已设法将其装入各种形状怪异的孔中。它不是万能的最佳工具,但当你只有一把锤子时,一切看起来都像钉子。

    【讨论】:

      【解决方案4】:

      一切都不是关于表现的,表现仍然是仅次于能力的。您首先获得一些语言(re:javascript)以使网站成为可能,然后改进语言。如果你从 JS 中剥离出 DOM 操作,让它编译为本机代码,那么我们将在 Web 上使用什么? javascript 存在的原因之一,我们不在 web 中使用 C/C++ 是因为它具有执行 DOM 操作的能力,它不需要编译成机器特定的格式,因此是通用的可执行文件。

      除此之外,我还有一个 javascript 的名称,它已经被剥离了 DOM 操作、静态类型、提前编译:它是 Java :)

      您的问题确实是我们为什么不将 Java 用于网站,因为它的性能要好得多 - 想想看。有一天我们会在那里,但还没有。

      【讨论】:

      • -1:Java 和 JavaScript 与梨和苹果笔记本电脑差不多。另外:Java Applet 被经常使用,直到 JavaScript 得到更广泛的使用......有一天,我们在那里,今天,我们不想回去
      • 好吧,如果你问别人java和javascript的主要区别是什么,我上面提到的三个肯定会出现。然而,我并没有声称它们是相似的——我上面使用的措辞本来可以更好。
      • 你还没有接近。 JS 是一种多范式语言,对函数式编程有强烈的偏好。这是以英里为单位的最大差异。那是第一,你没有提到。将 JS 与 Java 进行比较就像将 JS 与 C++ 进行比较……它们是不同的语言,彼此独立开发。这种混淆的唯一原因是名称。 JS 最初被称为 LiveScript BTW,在这个名称中没有任何类似于 Java 的东西
      • 我认为 Zasz 的意思是说,一种静态类型的、提前编译的、无 domless 语言已经在浏览器中尝试过并且失败了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-15
      • 2020-01-12
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      • 1970-01-01
      • 2010-09-29
      相关资源
      最近更新 更多