Javascript performance of Array.map



刚刚在jsperf中编写了一些测试用例,以测试在使用Array.map和其他替代方案时命名函数和匿名函数之间的差异。

http://jsperf.com/map-reduce-named-functions

(请原谅url名称,这里没有Array.reduce的测试,我在完全决定要测试什么之前命名了测试)

简单的for/while循环显然是最快的,但我仍然对慢10倍以上的Array.map感到惊讶。。。

然后我尝试了mozilla的polyfillhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill

Array.prototype.map = function(fun /*, thisArg */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var res = new Array(len);
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++)
{
// NOTE: Absolute correctness would demand Object.defineProperty
//       be used.  But this method is fairly new, and failure is
//       possible only if Object.prototype or Array.prototype
//       has a property |i| (very unlikely), so use a less-correct
//       but more portable alternative.
if (i in t)
res[i] = fun.call(thisArg, t[i], i, t);
}
return res;
};

然后我尝试了一个我自己编写的简单实现。。。

Array.prototype.map3 = function(callback /*, thisArg */) {
'use strict';
if (typeof callback !== 'function') {
throw new TypeError();
}
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0, len = this.length; i < len; i++) {
this[i] = callback.call(thisArg, this[i], i, this);
};
};

结果摘要:

从最快到最慢:

  1. 对于simple/while(大致相同)
  2. Map3(我自己的实现)
  3. Map2(Mozilla polyfill)
  4. Array.map
  5. 中的

观察

一个有趣的注意事项是,命名函数通常比使用匿名函数快一点(大约5%)。但我注意到,在firefox中,命名函数的polyfill速度较慢,但在chrome中速度较快,但chrome自己的map实现在命名函数中速度较慢。。。我每个测试了大约10倍,所以即使它不是严格的测试(jsperf已经做了),除非我的运气很好,否则它应该足够作为一个指南。

此外,chrome的map功能比我机器上的firefox慢2倍。完全没想到。

而且。。。firefox自己的Array.map实现比Mozilla Polyfill慢。。。哈哈

我不知道为什么ECMA-262规范规定map可以用于数组以外的对象(http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.19)。这使得整个映射函数慢3-4倍(如我的测试所示),因为你需要在每个循环中检查属性是否存在。。。

结论

如果考虑到不同的浏览器执行的略有不同,那么命名函数和匿名函数之间并没有太大区别。

最后,我们不应该真的进行太多的微优化,但我发现这很有趣:)

首先,这不是一个公平的比较。正如您所说,正确的javascript映射能够使用对象,而不仅仅是数组。所以你基本上是在比较两个完全不同的函数,它们有不同的算法/结果/内部工作。

当然,正确的javascript映射更慢——它被设计为在更大的域上工作,而不是在简单的数组上工作。

我只想分享一些我认为与此相关的发现。我对.map有一些问题。切换到哈希图大大降低了速度。

我们有一个跨越20万个小对象的映射函数,将该映射转换为哈希对象并重新创建数组,使其从20min变为0.4s

第一次进近(20分钟):

const newArr = arr1.map((obj) => {
const context1 = arr2.find(o => o.id === obj.id)
const context2 = arr3.find(o => o.id === obj.id)
return { ...obj, context1, context2 }
})

新方法

const newArrObj = {}
arr1.forEach(o => newArrObj[o.id] = o)
arr2.forEach(o => newArrObj[o.id].context1 = o)
arr3.forEach(o => newArrObj[o.id].context2 = o)
const users = []
arr1.forEach(o => users[users.length] = newArrObj[o.id])

相关内容

  • 没有找到相关文章

最新更新