“All in Cloud”之后,和你聊聊「云原生DevOps的Kubernetes技巧」 了解详情
写点什么

Facebook 开源 JavaScript 代码优化工具 Prepack

  • 2017 年 5 月 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 年 5 月 04 日 19:003429
用户头像

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

关注

评论

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

VuePress 博客之 SEO 优化(五)添加 JSON-LD 数据

冴羽

Vue 前端 vuepress SEO 博客搭建

信创云管理平台,头部券商解决异构云资源管理的关键

BoCloud博云

信创 云管平台

安全大讲堂 | 孙朝晖:全量数据是一切网络安全分析的起点

腾讯安全云鼎实验室

数据分析 网络安全 数据安全 安全大讲堂

聊聊数仓中TPCD-DS&TPC-H与查询性能的那些事儿

华为云开发者社区

编辑器 GaussDB(DWS) TPCD-DS TPC-H 查询性能

大咖说|试衣到家 CEO:我们卖的不是衣服,是服务

大咖说

阿里巴巴 科技 时尚产业 试衣到家

3. 堪比JMeter的.Net压测工具 - Crank 进阶篇 - 认识bombardierdate

MASA技术团队

C# .net 测试 压测 测试工具

如何进行高效的版本管理,版本管理的方法

阿里云云效

云计算 阿里云 项目管理 云原生 版本管理

【网络安全】网络安全的重要性你知道吗?

行云管家

网络安全

小程序多端引流新思路:App公域流量挖掘

Speedoooo

APP开发 智慧终端 引流获客工具 引流获客系统

《Mybatis 手撸专栏》第1章:开篇介绍,我要带你撸 Mybatis 啦!

小傅哥

小傅哥 mybatis 手写Mybatis

ironSource 推出全球首个跨渠道应用营销平台 ironSource Luna

科技热闻

成都大运会“数智竞技邀请赛”启动 开悟平台为全球青年提供竞技舞台

科技热闻

集结创新力量,2022航天宏图&华为云杯PIE软件开发者大赛正式开启

科技热闻

OceanBase 源码解读(八):事务日志的提交和回放

OceanBase 数据库

oceanbase 源码解读

Linux之uniq命令

入门小站

Linux

深度揭秘阿里云 Serverless Kubernetes

Serverless Devs

API接口知识小结

源字节1号

程序员 有趣的技术知识

Redis面试题:基本数据类型与底层存储结构

Linux服务器开发

redis 面试题 Linux服务器开发 Linux后台开发 BAT面试题

运维审计系统是堡垒机么?跟堡垒机有啥区别?

行云管家

运维 堡垒机 运维审计系统

如何实现24小时客户服务

小炮

客户服务

即学即会 Serverless 系列:初识 Serverless 架构

Serverless Devs

云计算 阿里云 Serverless 架构

教你两分钟做出一个精美好用的404页面

源字节1号

前端开发 后端开发 网页开发

在线JSON转HTML,TABLE表格工具

入门小站

工具

如何使用Java AWT 创建一个简易计算器

华为云开发者社区

Java 计算器 GUI AWT 图形

小程序容器轻松打造轻应用生态平台

Speedoooo

APP开发 小程序容器 轻应用 快应用 超级app

在线HTML压缩格式化工具

入门小站

工具

企业知识管理的措施

小炮

知识管理

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