@lenville
2017-05-04T06:07:12.000000Z
字数 3431
阅读 719
Facebook JavaScript Prepack
5月4日,Facebook开源团队技术作者Joel Marcey在Hacker News社区发布一则《Prepack帮助提高JavaScript代码的效率》,引起了社区的广泛讨论。
官方宣称Prepack是一个优化JavaScript源代码的工具,实际上它是一个JavaScript的部分求值器(Partial Evaluator),可在编译时执行原本在运行时的计算过程,并通过重写JavaScript代码来提高其执行效率。Prepack用简单的赋值序列来等效替换JavaScript代码包中的全局代码,从而消除了中间计算过程以及对象分配的操作。对于重初始化的代码,Prepack可以有效缓存JavaScript解析的结果,优化效果最佳。
以下五个概念可以帮助你更好地理解Prepack的运行机制:
具体执行(Concrete Execution)
Prepack的核心是一个JavaScript解释器,它与ECMAScript 5几乎完全兼容,而且紧密地保持与ECMAScript 2016语言规范的一致性,你可以将Prepack中的解释器视为完全参照JavaScript实现的。
解释器能够跟踪并撤销包括所有对象Mutation在内的结果,从而能够进行推测优化(Speculative Optimization)。
Date.now可以返回一个抽象值,你可以通过helper辅助函数(如__abstract())手动注入抽象值。Prepack会跟踪所有在抽象值上执行的操作,在遇到分支时,Prepack会执行并探索所有可能性。所以,Prepack实现了一套JavaScript的符号执行引擎。以下是官方提供的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团队对未来的规划: