原文:Parsing in V8 explained

本文档介绍了 V8 引擎是如何解析 JavaScript 源代码的,以及我们将改进它的计划。

动机

我们有个解析器和一个更快的预解析器(~2x),但是预解析器对大多数现代 JavaScript 无用。此外假如还没有编译了外部函数,否则我们必须再解析一遍内部函数。 那现在的 V8 引擎什么时候会立即编译(eager compilation)呢?

  1. 顶层的括号函数(function...

  2. 在 ( 之后的不是函数声明的内部函数

当我们把一个内部函数当做非脚本级的一部分来解析的时候,是不能使用预解析器的。我们将不会编译一个内部函数,所以如果我们永远不先行编译函数,那么一般的 n 层嵌套函数会先被预解析,然后会有 n 次解析(以及一次编译)。或从另一方面来看待它,考虑了以下格式的顶级“模块”:

  1. !function f() {
  2. function A() {
  3. function B() {...}
  4. }
  5. function C() {
  6. function D() {...}
  7. }
  8. ...
  9. }(), function g() {....}()

压缩程序经常用 (function() {...})();(function(){...}))() 替换上面的代码。但是,你可以看到它没有被括号括起来,所以我们不会在顶层运行完整的解析器。这是为什么呢?因为我们不知道这些函数会被立即调用。因此会使用更快的预解析器。但是确实需要这些函数,这就打脸了,而 V8 就不得不去再解析。预解析阶段会将整个顶层函数看一遍,包括 A, B, C, D(假如原本的 (function f() {...})() 编译过那么就会跳过本阶段)。

因为顶层函数被调用了,所以引擎会去解析它。这次解析是完全的。为什么呢?因为需要做范围解析以便知道在哪里分配变量。而唯一的正确的方式是知道什么变量被引用了。而知道什么变量被引用的唯一方式是对内部函数也进行完全的解析。所以解析/编译顶层函数会迫使引擎对 A,B,C,D 这些函数也进行完全解析。

现在我们需要调用函数 A,因此需要去编译它。为了解析它,我们也需要知道在哪里分配变量。就像我说的:你需要知道从内部函数引用了上面。所以我们完全解析了 B 函数。

现在我们假定预解析需要1费,解析需要2费。编译它需要另外的2费,但是我们实际上编译的是压缩的版本,因此可以忽略。 假如现在运行 A 函数,那么将花费 3*(f + A + B) + 2*(A + B)。如果 A 将会调用 B,我们就花费另外的2费用于 B 函数。

一方面,要得到一个内部函数,你需要解析一大堆。 另一方面,顶层函数越多,解析它的成本就越高,因为你要算上解析所有嵌套函数的时间。

建议的解决方案

那么计划怎么解决呢?

  1. 预解析的同时也进行范围解析(scope resolution),这样未编译部分的花费会从2降低到1.x。

  2. 将函数的上下文内存分配信息序列化到持久存储中,以避免不必要的重解析成本。

  3. 立即编译可能会支持 ! 和 , 。

至于成本?所有懒解析函数在初始加载时的开销为1.x,如果实际使用则为3.x。.x是内部函数范围解析和序列化的额外未知成本。

立即编译的优点是,对于已知的立即执行的顶级函数,我们可以进一步将成本从3.x下降到2。它是从顶层向内的。如果我们决定不将预解析(eagerly parse)作为主编译工作的一部分,那么我们可以等到它被执行,这样我们至少可以确定只需要支付实际使用的功能的编译成本(2解析和2编译)。

立即编译的缺点是我们需要在解析和编译之间在内存中保持AST(Abstract syntax tree)。显著增加了使用内存的峰值。如果我们可以预解析那些在被立即解析的函数的内部函数,情况可能会看起来好多了。即使如此,在低内存设备上,我们应该禁用启发式的立即编译。

如果我们序列化这些数据,那么在热启动时就完完全全不需要去查看未使用的代码。热启动时,即使在顶层的时候也是与启发式的立即编译不相关,因为我们将只解析/编译我们需要的函数。 搭载了比使用的代码还要多10倍以上的页面将会立即热启动。(目前已经可以是这种情况,但它是一个有点hit-and-miss)。

相关链接:

1.Abstract syntax tree

[翻译] V8引擎的解析的更多相关文章

  1. 深入V8引擎-引擎内部类管理解析

    v8的初始化三部曲,前面花了三篇解决了第一步,由于只是生成了一个对象,第二步就是将其嵌入v8中,先看一下三个步骤. // 生成默认Platform对象 std::unique_ptr<v8::P ...

  2. jQuery 2.0.3 源码分析Sizzle引擎 - 词法解析

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 浏览器从下载文档到显示页面的过程是个复杂的过程,这里包含了重绘和重排.各家浏览器引擎的工作原理略有差别,但也有一定规则. 简 ...

  3. 分析Sizzle引擎 - 词法解析

    分析Sizzle引擎 - 词法解析 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 浏览器从下载文档到显示页面的过程是个复杂的过程,这里包含了重绘和重排.各家浏览器引擎的工 ...

  4. V8引擎嵌入指南

    如果已读过V8编程入门那你已经熟悉了如句柄(handle).作用域(scope)和上下文(context)之类的关键概念,以及如何将V8引擎作为一个独立的虚拟机来使用.本文将进一步讨论这些概念,并介绍 ...

  5. JavaScript工作机制:V8 引擎内部机制及如何编写优化代码的5个诀窍

    概述 JavaScript引擎是一个执行JavaScript代码的程序或解释器.JavaScript引擎可以被实现为标准解释器,或者实现为以某种形式将JavaScript编译为字节码的即时编译器. 下 ...

  6. JavaScript是如何工作的02:深入V8引擎&编写优化代码的5个技巧

    概述 JavaScript引擎是执行 JavaScript 代码的程序或解释器.JavaScript引擎可以实现为标准解释器,或者以某种形式将JavaScript编译为字节码的即时编译器. 以为实现J ...

  7. 深入浏览器工作原理和JS引擎(V8引擎为例)

    浏览器工作原理和JS引擎 1.浏览器工作原理 在浏览器中输入查找内容,浏览器是怎样将页面加载出来的?以及JavaScript代码在浏览器中是如何被执行的? 大概流程可观察以下图: 首先,用户在浏览器搜 ...

  8. 高性能JavaScript模板引擎原理解析

    随着 web 发展,前端应用变得越来越复杂,基于后端的 javascript(Node.js) 也开始崭露头角,此时 javascript 被寄予了更大的期望,与此同时 javascript MVC ...

  9. 精读《V8 引擎 Lazy Parsing》

    1. 引言 本周精读的文章是 V8 引擎 Lazy Parsing,看看 V8 引擎为了优化性能,做了怎样的尝试吧! 这篇文章介绍的优化技术叫 preparser,是通过跳过不必要函数编译的方式优化性 ...

随机推荐

  1. openresty 前端开发序

    还记得第一次尝试前后端分离的时候,是使用nginx + react 构建的spa应用,后端是java,主要处理业务逻辑逻辑部分,返回json数据,在nginx里面配置好html + js纯静态文件,再 ...

  2. spring源码:核心组件(li)

    一.AOP实现 Spring代理对象的产生:代理的目的是调用目标方法时我们可以转而执行InvocationHandler类的invoke方法,所以如何在InvocationHandler上做文章就是S ...

  3. Javaweb项目框架搭建-准备篇

    前言Java从大二开始学习到现在大四也有差不多两年了,但是由于之前一直在玩,没有认真学过,直到现在才开始重新学习.也是很凑巧,看到了黄勇老师的<架构探险>,于是便开始学习写Java Web ...

  4. 如何利用FineReport制作动态树报表

    在对数据字段进行分类管理时,利用动态树折叠数据是一个很好的方法,也就是点击数据前面的加号才展开对应下面的数据,如下图.那这样的效果在制作报表时该如何实现呢? 下面以报表工具FineReport为例介绍 ...

  5. ArcGIS Engine开发前基础知识(3)

    对象模型图 一.对象模型图中的类与接口 ArcGIS Engine 提供大量的对象,这些对象之间存在各种各样的关系,如继承.组合.关联等.对象模型图(Object model diagram,ODM) ...

  6. java web之个人通讯录系统

    前天下了第一场雪,专业课老师给我们布置了一个期末小作业,真的感觉到寒假就要来临了.这个学期没过多久就要结束了.总结这学期,感觉还是有不少收获的.完成了当初许下的诺言,现在也越来越喜欢软件这个行业了,虽 ...

  7. TabLayout+ViewPager+Fragment制作页卡

    本人很懒,直接上代码了. 布局文件: <?xml version="1.0" encoding="utf-8"?><android.suppo ...

  8. Android XML中引用自定义内部类view的四个why

    今天碰到了在XML中应用以内部类形式定义的自定义view,结果遇到了一些坑.虽然通过看了一些前辈写的文章解决了这个问题,但是我看到的几篇都没有完整说清楚why,于是决定做这个总结. 使用自定义内部类v ...

  9. oracle容器化docker解决方案

    Docker提供了轻量级的虚拟化,它几乎没有任何额外开销. 提供了一个从开发到上线均一致的环境. 开发效率:一是我们想让开发环境尽量贴近生产环境 二是我们想快速搭建开发环境   基于docker研发小 ...

  10. centos6环境下搭建irc服务器

    问题描述 有时候逛技术社区,经常会发现有个叫IRC的东西存在,想搭建下看看到底是个什么东西 说明: 操作系统环境为CentOS6.5_64 安装irc服务器 通过yum进行安装,命令如下: yum i ...