JS代码优化工具Prepack

时间:2021-11-17 03:45:19

 

  最近,Facebook 发布 Prepack :一个优化 JavaScript 源代码的工具,实际上它是一个 JavaScript 部分求值器(Partvaluator),可在编译时执行原本在运行时的计算过程,并通过重写 JavaScript 代码来提高其执行效率。(西安尚学堂

  Prepack 用简单的赋值序列来等效替换 JavaScript 代码包中的全局代码,从而消除了中间计算过程以及对象分配的操作。对于重初始化的代码,Prepack可以有效缓存JavaScript解析的结果,优化效果最佳。

 

  下面五个概念可以帮我们更好的理解 Prepack 运行机制:

  抽象语法树(AST)Prepack运行在AST级别,使用Babel解析并生成JavaScript源代码。

 

  具体执行(Concrete Execution)Prepack 核心是一个JavaScript解释器,它与ECMAScript 5几乎完全兼容,而且紧密地保持与ECMAScript 2016语言规范的一致性,你可以将Prepack中的解释器视为完全参照JavaScript实现的。解释器能够跟踪并撤销包括所有对象Mutation在内的结果,从而能够进行推测优化(Speculative Optimization)。

 

  符号执行(Symbolic Execution)除了对具体值进行计算外,Prepack的解释器还可以操作受环境相互作用影响的抽象值。例如Date.now可以返回一个抽象值,你可以通过helper辅助函数(如__abstract())手动注入抽象值。Prepack会跟踪所有在抽象值上执行的操作,在遇到分支时,Prepack会执行并探索所有可能性。所以,Prepack实现了一套JavaScript的符号执行引擎。

 

  抽象释义(Abstract Interpretation)符号执行在遇到抽象值的分支时会分叉(fork),Prepack会在控制流合并点加入分歧执行(Diverged Execution)来实现抽象释义的形式。连接变量和堆属性可能会得到条件抽象值,Prepack会跟踪有关抽象值和型域(Type Domain)的信息。

 

  堆序列化(Heap Serialization)当全局代码返回,初始化阶段结束时,Prepack捕获最终的堆并按顺序排列堆栈,生成直观的JavaScript新代码,创建并链接初始化堆中可访问的所有对象。堆中的一些值可能是抽象值的计算结果,对于这些值,Prepack将生成原始程序完成计算所执行的代码。

 

  以下是官方提供的Prepack优化示例:

  

/* Hello World */

  // Input

  (function () {

  function hello() { return 'hello'; }

  function world() { return 'world'; }

  global.s = hello() + ' ' + world();

  })();

  // Output

  (function () {

  s = "hello world";

  })();

  /* 消除抽象税 */

  // Input

  (function () {

  var self = this;

  ['A', 'B', 42].forEach(function(x) {

  var name = '_' + x.toString()[0].toLowerCase();

  var y = parseInt(x);

  self[name] = y ? y : x;

  });

  })();

  // Output

  (function () {

  _a = "A";

  _b = "B";

  _4 = 42;

  })();

 

  Prepack团队对未来的规划如下:

  1、短期

  稳定现有功能集,用于预优化(Prepack)React Native代码包

  集成React Native工具链

  根据React Native所用模块系统的假设来构建优化

  2、中期

  进一步优化序列化(Serialization),包括:消除不暴露特性(identity)的对象;消除未使用的导出属性,等等

  预优化每个函数、基本代码块、语句、表达式

  与ES6保持完全一致

  支持广泛的模块系统

  假设ES6支持某些功能,延迟完成或直接忽略Polyfill应用

  进一步实现Web和Node.js环境中的兼容性目标

  深入集成JavaScript虚拟机,改进堆反序列化过程,包括 :暴露“对象懒初始化”的概念 - 以一种JavaScript无感知的方式,在首次使用对象时对其进行初始化;通过专门的字节码提高普通对象创建的编码效率;将代码分为两个阶段:1) 非环境依赖阶段,虚拟机可以安全地捕获并恢复生成的堆;2)环境依赖阶段,通过从环境中获得的值执行所有剩余的计算过程来拼凑具体的堆,等等

  总结循环和递归

  3、长期 - 利用Prepack作为一个平台

  JavaScript Playground - 通过调整JavaScript引擎体验JavaScript特性,这些引擎由JavaScript所编写,托管在浏览器中;你可以把它想象成一个“Babel虚拟机”,实现了不能被编译的JavaScript新特性

  捕捉Bug - 发现异常崩溃、执行问题……

  效果分析,例如检测模块工厂函数可能的副作用或强制纯净注释