2014-09-13 169 views
5

阅读文档时,我发现了一个简单的优化,大大提高了JavaScript的性能。Javascript功能优化(`)`

原始代码:

function parseRow(columns, parser) { 
    var row = {}; 
    for (var i = 0; i < columns.length; i++) { 
    row[columns[i].name] = parser.readColumnValue(); 
    } 
} 

优化代码:

var code = 'return {\n'; 
columns.forEach(function(column) { 
    code += '"' + column.name + '":' + 'parser.readColumnValue(),\n'; 
}); 
code += '};\n'; 

var parseRow = new Function('columns', 'parser', code); 

这里找到:https://github.com/felixge/faster-than-c
为什么它运行快20%?
我相信它会删除for语句,但不会有forEach具有相同的计算成本?

+0

它是否在谈论20%的功能创建逻辑本身?或者每次调用函数parseRow?如果是后一种情况,我会假设增益发生是因为优化代码中没有for循环。 (在第一种情况下,for循环会在每次调用parseRow函数时运行,并且多次调用columns.length属性也可能归因于原始代码的缓慢性,只是我的2美分:)) – 2014-09-13 13:10:51

+1

相关(对于V8)http ://www.youtube.com/watch?v = UJPdhx5zTaw – 2014-09-13 13:21:30

+1

当'columns'的大小足够大时,'优化后的代码'似乎没有更快。请参阅[jsPerf](http://jsperf.com/javascript-optimization-with-new-function) – rhgb 2014-09-13 14:02:48

回答

5

不同之处在于您只使用forEach构造的优化函数。创建函数后,内部没有任何循环:loop is unrolled和列名称为hardcoded。然后将该方法编辑为一个工作函数,该函数甚至可以编译为机器代码depending on the engine。这将导致两个性能方面的改进:

  1. 通过消除for循环条件检查(i < columns.length)完全,没有分支,并
  2. 通过硬编码的column[i].name值转换成多个语句,你删除评估column[i]和查找到column.name在每一步。

所以调用new Function(...)与作为String通过代码后,您parseRow变量得到参照以下功能:

function parseRow(columns, parser) { 
    return { 
     "columnOne": parser.readColumnValue(), 
     "columnTwo": parser.readColumnValue(), 
     "columnThree": parser.readColumnValue(), 
     ... 
    }; 
} 

注意,没有任何的循环,分支,或其他查询在该代码中,除了多个parser.readColumnValue()调用。

这为什么在JavaScript中可能?

在JavaScript中如此高效地工作的原因是因为任何网页中的JavaScript源代码无论如何都需要由JS引擎解释或编译。你不会发布你的网页编译的可执行文件,甚至(有些)预编译的字节码(如Java或.NET)。每载入一个新的.js文件,浏览器在运行之前都会从头开始编译它(呃,确切地说,在现代引擎中,它是解释和编译之间的东西,即JITting)。

这意味着在运行时从字符串(即编译代码)创建工作函数的效率并不比从手写代码读取.js文件低。与C/C++程序比较,该程序编译为机器码(即可执行文件尽可能靠近CPU)before it reaches the customer(在所有合理的情况下)。

如果你想在C++(一种self-modifying code)中做到这一点,你将不得不捆绑一个编译器沿着你的应用程序来构建代码,并且构建这个函数的代价会超过你获得的好处你最终会开始它。例如,在.NET中,对于程序emit methods or even assemblies at run time而言,这并不罕见,然后它将JIT编译为机器代码,以允许潜在的性能改进,例如您的问题。

2

性能提升取决于JavaScript引擎以及正在处理的数据。我们不知道“快20%”的确切情况(除了使用node.js)。在某些情况下它可能会变慢。 (编辑:您需要经常调用该功能足以超过建设成本)。增益的一些可能原因:

优化后的代码会创建一个对象字面值。以前的版本不断地将值分配给不存在的属性。这有一些相关的成本。

row[columns[i].name]有三个查找,而优化版本没有,一旦函数被构造。不要忘记,row[columns[i].name]尚不存在,所以查找更昂贵。 columns.length也是查找。