写点什么

Facebook 开源 JavaScript 代码优化工具 Prepack

  • 2017-05-04
  • 本文字数:2528 字

    阅读完需:约 8 分钟

5 月 4 日,Facebook 开源团队技术作者 Joel Marcey 在 Hacker News 社区发布一则《 Prepack 帮助提高 JavaScript 代码的效率》,引起了社区的广泛讨论

官方宣称 Prepack 是一个优化 JavaScript 源代码的工具,实际上它是一个 JavaScript 的部分求值器(Partial Evaluator),可在编译时执行原本在运行时的计算过程,并通过重写 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;
})();
复制代码
/* 斐波那契 */
// Input
(function () {
function fibonacci(x) {
return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
}
global.x = fibonacci(23);
})();
// Output
(function () {
x = 28657;
})();
复制代码
/* 模块初始化 */
// Input
(function () {
let moduleTable = {};
function define(id, f) { moduleTable[id] = f; }
function require(id) {
let x = moduleTable[id];
return x instanceof Function ? (moduleTable[id] = x()) : x;
}
global.require = require;
define("one", function() { return 1; });
define("two", function() { return require("one") + require("one"); });
define("three", function() { return require("two") + require("one"); });
define("four", function() { return require("three") + require("one"); });
})();
three = require("three");
// Output
(function () {
function _2() {
return 3 + 1;
}
var _1 = {
one: 1,
two: 2,
three: 3,
four: _2
};
function _0(id) {
let x = _1[id];
return x instanceof Function ? _1[id] = x() : x;
}
require = _0;
three = 3;
})();
复制代码
/* 环境相互作用与分支 */
// Input
(function(){
function fib(x) { return x <= 1 ? x : fib(x - 1) + fib(x - 2); }
let x = Date.now();
if (x === 0) x = fib(10);
global.result = x;
})();
// Output
(function () {
var _0 = Date.now();
if (typeof _0 !== "number") {
throw new Error("Prepack model invariant violation");
}
result = _0 === 0 ? 55 : _0;
})();

目前 Prepack 仍处于早期开发阶段,尚未准备好在生产环境中使用,官方建议仅尝试使用,并欢迎提供反馈以帮助修复错误。

以下是 Prepack 团队对未来的规划:

  • 短期
    • 稳定现有功能集,用于预优化 (Prepack)React Native 代码包
    • 集成 React Native 工具链
    • 根据 React Native 所用模块系统的假设来构建优化
  • 中期
    • 进一步优化序列化(Serialization),包括
      • 消除不暴露特性(identity)的对象
      • 消除未使用的导出属性
    • 预优化每个函数、基本代码块、语句、表达式
    • 与 ES6 保持完全一致
    • 支持广泛的模块系统
    • 假设 ES6 支持某些功能,延迟完成或直接忽略 Polyfill 应用
    • 进一步实现 Web 和 Node.js 环境中的兼容性目标
    • 深入集成 JavaScript 虚拟机,改进堆反序列化过程,包括
      • 暴露“对象懒初始化”的概念 - 以一种 JavaScript 无感知的方式,在首次使用对象时对其进行初始化
      • 通过专门的字节码提高普通对象创建的编码效率
      • 将代码分为两个阶段:1) 非环境依赖阶段,虚拟机可以安全地捕获并恢复生成的堆;2) 环境依赖阶段,通过从环境中获得的值执行所有剩余的计算过程来拼凑具体的堆
    • 总结循环和递归
  • 长期 - 利用 Prepack 作为一个平台
    • JavaScript Playground - 通过调整 JavaScript 引擎体验 JavaScript 特性,这些引擎由 JavaScript 所编写,托管在浏览器中;你可以把它想象成一个“Babel 虚拟机”,实现了不能被编译的 JavaScript 新特性
    • 捉 Bug - 发现异常崩溃、执行问题……
    • 效果分析,例如检测模块工厂函数可能的副作用或强制纯净注释
    • 类型分析
    • 信息流分析
    • 调用图推理,允许内联和代码索引
    • 自动测试生成,利用符号执行的特性与约束求解器(Constraint Solver)结合来计算执行不同执行路径的输入
    • 智能模糊 (Smart Fuzzing)
    • JavaScript 沙盒 - 以不可观察的方式有效地测试 JavaScript 代码
2017-05-04 19:004061
用户头像

发布了 63 篇内容, 共 133.2 次阅读, 收获喜欢 38 次。

关注

评论

发布
暂无评论
发现更多内容

一文吃透泛型

程序员大彬

Java java面试

MobPush创建推送

MobTech袤博科技

Selenium之POM 设计模式

QE_LAB

selenium 测试技术

AI日课@20230410:大语言模型是对本质知识的无损压缩

无人之路

ChatGPT

万字详解 | Java 函数式编程

Phoenix

Lambda 函数式 #java

毫末发布DriveGPT雪湖·海若!首期智能驾驶能力、驾驶场景识别能力对行业开放

科技大数据

Java变量与数据类型

timerring

Java 后端

大普微DapuStor完成阿里云PolarDB数据库产品生态集成认证

阿里云数据库开源

国产数据库 polarDB PolarDB-X PolarDB-PG 大普微

青云职上 群英有为 | 助力区域打造人才高地,龙岗双选会顺利举办!

科技说

数据库原理及MySQL应用 | 并发控制

TiAmo

MySQL 数据库 并发控制

上干货!小红书“薯条”业务竞价策略及最优公式详解

小红书技术REDtech

广告 机制策略

FLINK 在蚂蚁大规模金融场景的平台建设

Apache Flink

大数据 flink 实时计算

打卡智能中国(四):向着沙漠,向着沙漠

脑极体

AI 遥感

实力爆表,日日新成为AI领航者

柒号华仔

人工智能 AIGC 日日新 商汤

Mac上免费好用的PDF编辑器:Acrobat Reader DC2023

Rose

苹果软件 mac软件下载 pdf阅读 Adobe Acrobat Reader DC

得物 API一站式协作平台的一些思考

得物技术

API Gateway

华为云智能编程进高校,解读行业发展新趋势

科技说

在字节跳动实习后,程序员是这样写简历的

字节跳动技术范儿

字节跳动 实习

毫末顾维灏:中国首个自动驾驶数据智能体系MANA将以产品服务方式对外合作开放

科技大数据

CIO成就计划预告·微软韦青:数智时代下的企业数智化战略决策

科创人

降本增效不是“盲目减脂”,利用亚马逊云科技达成云成本正循环

Lily

例行汇报,看看 FinClip 3月都干了啥

FinClip

AI时代下的打工人 | 社区征文

Dec

三周年征文

技术速递 | 分布式政企应用如何快速实现云原生的微服务架构改造

科技说

高效复制:在Linux中并发执行相同任务,各自生成日志

小毛驴的烂笔头

软件测试/测试开发丨电商业务的性能测试必备基础知识

测试人

软件测试 Jmeter 性能测试 测试开发

码头风云——5G降临

脑极体

5G

Django笔记七之ManyToMany和OneToOne介绍

Hunter熊

Python django 多对多 ManyToMany OneToOne

CIO成就计划第二季第一期 | 活动回顾:基于数字技术重塑流程,驱动业务增长

科创人

数据产品经理的三大底层思维

Taylor

数据产品经理 产品思维 数据产品 数据思维 #商业思维

Facebook开源JavaScript代码优化工具Prepack_JavaScript_刘振涛_InfoQ精选文章