前言
-
是什么?
-
解决了什么问题?
-
带来了什么新的问题?
-
新的问题和解决的问题在目前场景下权重是怎么样的?
-
投入产出比如何?
一、什么是Prepack
二、工作原理
-
Abstract Syntax Tree (AST) 抽象语法树 (粒度) Prepack在抽象语法树的级别运行,使用 Babel解析并生成JavaScript源代码。 那什么是“在抽象语法树的级别运行”? 将一种结构化语言编译成另一个结构化语言的代码过程如下:
2、对抽象语法树(AST)进行遍历(traverse)和替换(replace) 生成新的 抽象语法树(AST);
-
Concrete Execution 具体执行 Prepack的核心是一个JavaScript解释器,它与ECMAScript 5几乎完全兼容,而且紧密地保持与 ECMAScript 2016语言规范的一致性,你可以将Prepack中的解释器视为完全参照JavaScript实现的。
-
Symbolic Execution 符号执行 除了对具体值进行计算外,Prepack的解释器还可以操作受环境相互作用影响的抽象值。例如Date.now可以返回一个抽象值,你可以通过helper辅助函数(如__abstract())手动注入抽象值。Prepack会跟踪所有在抽象值上执行的操作,在遇到分支时,Prepack会执行并探索所有可能性。所以,Prepack实现了一套JavaScript的符号执行引擎。 以上是官网的翻译,就是符号可以代表一个根据环境不同而可变的一个方法执行结果,例如以下例子中的_0就是这样的一个抽象值,它无法提前计算,因为在不同的浏览器或运行时机下结果是不同的。左边编译前代码,x 存在if 判断的分支情况,Prepack会汇总所有的分支情况进行优化编译,如例子中将所有分支汇总(2个分支)替换成三目运算符表达。
-
Abstract Interpretation 抽象释义 符号执行在遇到抽象值的分支时会分叉(fork),Prepack会在控制流合并点加入分歧执行(Diverged Execution)来实现抽象释义的形式。连接变量和堆属性可能会得到条件抽象值,Prepack会跟踪有关抽象值和型域(Type Domain)的信息。 还是之前的例子,就是抽象值“_0 ” 存在2个分支,Prepack底层会汇总分支情况,生成新的抽象语法树,在优化解析时(Generator)通过连接变量和堆属性,得到各分支下的抽象值“_0 ”可能的对应情况,并跟踪相关情况的信息计算出结果形成新的代码。
-
Heap Serialization堆序列化
-
开发的代码经过解析(Parse)形成抽象语法树
-
Transform时期预先计算出的可求的值,对存在受环境影响的抽象值进行抽象释义,转换成新的抽象树
-
Generate时期按顺序遍历堆进行符号执行和跟踪有关抽象值和型域信息处理抽象值等,最终组成新的代码。
三、示例
四、Prepack 引入会带来的问题
-
没有官方统一、成熟的方案支持打包集成到开发环境——需要开发者另辟蹊径完成集成
-
不能识别 document 和 window,会识别为 undefined——浏览器环境代码利用Prepack存在较大局限性
-
没有完全支持浏览器环境和node.js环境——node代码不能全面接入Prepack
-
生成的代码没有针对引擎做好优化——运行效率会存在变低的情况
-
存在一些尚未解决的issues——会有更多的“坑”需要踩
五、Prepack 未来规划
-
稳定现有功能集,用于预优化(Prepack)React Native代码包
-
集成React Native工具链
-
根据React Native所用模块系统的假设来构建优化
-
进一步优化序列化(Serialization),包括:消除不暴露特性(identity)的对象;消除未使用的导出属性,等等
-
预优化每个函数、基本代码块、语句、表达式
-
与ES6保持完全一致
-
支持广泛的模块系统
-
假设ES6支持某些功能,延迟完成或直接忽略Polyfill应用
-
进一步实现Web和Node.js环境中的兼容性目标
-
深入集成JavaScript虚拟机,改进堆反序列化过程,包括 :暴露“对象懒初始化”的概念 - 以一种JavaScript无感知的方式,在首次使用对象时对其进行初始化;通过专门的字节码提高普通对象创建的编码效率;将代码分为两个阶段:1) 非环境依赖阶段,虚拟机可以安全地捕获并恢复生成的堆;2)环境依赖阶段,通过从环境中获得的值执行所有剩余的计算过程来拼凑具体的堆,等等
-
总结循环和递归
-
JavaScript Playground - 通过调整JavaScript引擎体验JavaScript特性,这些引擎由JavaScript所编写,托管在浏览器中;你可以把它想象成一个“Babel虚拟机”,实现了不能被编译的JavaScript新特性
-
捉Bug - 发现异常崩溃、执行问题……
-
效果分析,例如检测模块工厂函数可能的副作用或强制纯净注释
-
类型分析
-
信息流分析
-
调用图推理,允许内联和代码索引
-
自动测试生成,利用符号执行的特性与约束求解器(Constraint Solver)结合来计算执行不同执行路径的输入
-
智能模糊(Smart Fuzzing)
-
JavaScript沙盒 - 以不可观察的方式有效地测试JavaScript代码