QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

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:004129
用户头像

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

关注

评论

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

LED电子屏厂家解密:LED控制系统的硬件设计

Dylan

系统 电子 LED display LED显示屏 市场

Python爬虫实战:调用微店商品详情接口(Micro.item_get)

代码忍者

API 接口 pinduoduo API

SmoothScroll for mac v1.6.0永久激活版 鼠标增强工具

Rose

比赛放榜!开源!Workshop!阿里妈妈将在国际顶会NeurIPS打出一键三连

新消费日报

Cinema 4D 2023激活补丁(C4D 2023中文版)-Mac/win

Rose

TunesKit Subtitle Editor Mac版 功能强大的字幕编辑工具

Rose

以数据驱动增长,火山引擎数智平台“数据找人”为双12营销提效

字节跳动数据平台

电商 数据飞轮 双十二

面向金融场景的大模型 RAG 检索增强解决方案

阿里云大数据AI技术

人工智能 最佳实践 rag PAI

ExpressBurn Plus for Mac(DVD光盘刻录工具)

Mac相关知识分享

Navicat Premium 15 for Mac(数据库开发工具)中文版

Mac相关知识分享

音视频编解码SDK开发的流程

北京木奇移动技术有限公司

音视频开发 音视频技术 软件开发定制

京东商品详情数据接口(JD.item_get)丨京东API接口代码指南

tbapi

京东API接口 京东商品详情接口 京东商品数据采集

CST软件如何得到方向性系数随频率扫描的曲线

思茂信息

教程 仿真 cst

安全研究年终总结-分享2024年RCE类的CVE漏洞高危EXP集合!

安全乐谷

网络安全 数据安全 安全漏洞 漏洞分析 安全扫描

HarmonyOS开发宝典震撼来袭,卓越应用开发之旅一触即发,轻松启程!

HarmonyOS开发者

得物商家客服从Electron迁移到Tauri的技术实践

得物技术

typescript rust Vue 前端 前端 electron

Agisoft Metashape Professional 高精度3D模型 + 多格式支持,协同工作无忧

Rose

Word 2024 LTSC for Mac(word 2024)永久破解版

Rose

曲靖具有资质等保测评机构在哪里?电话多少?

行云管家

等保 堡垒机 等保评测 曲靖

Renamer 7 for mac 中文激活版 最好的批处理文件重命名工具

Rose

DispCam DisneyPlus Video Downloader for Mac(迪士尼视频下载工具)v1.1.1 激活版

Rose

Acrobat Pro DC 2024 for mac (PDF编辑转换器)中文版

Mac相关知识分享

考核信息化管理平台(源码+文档+部署+讲解)

深圳亥时科技

Coolmuster Android Assistant for Mac(Android管理工具)

Mac相关知识分享

BetterDisplay Pro Mac(屏幕显示优化工具)

Mac相关知识分享

DaisyDisk for Mac:可视化磁盘清理,释放空间超轻松

Rose

铁路运输行业怎么定义?为什么要用到堡垒机?

行云管家

等保 堡垒机 铁路行业 运输

智源Aquila-VL-2B模型成为首个Linux基金会MOF评级达到“最开源”Class I等级的模型

智源研究院

工单+远程技术支持一个方案就搞定!贝锐向日葵技术支持方案升级

科技热闻

PHP爬虫的使用与开发

科普小能手

php 爬虫 爬虫教程 PHP开发

Understand for Mac(优秀的源代码审查工具)

Rose

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