簡體   English   中英

Array.map 的 Javascript 性能

[英]Javascript performance of Array.map

剛剛在 jsperf 中編寫了一些測試用例來測試命名函數和匿名函數之間的區別,同時使用Array.map和其他替代方法。

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

(請原諒 url 名稱,這里沒有測試Array.reduce ,我在完全決定要測試什么之前命名了測試)

一個簡單的 for/while 循環顯然是最快的,但我仍然對Array.map慢 10 倍以上感到驚訝......

然后我嘗試了 mozilla 的 polyfill https://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. 對於簡單/同時(大致相同)
  2. Map3(我自己的實現)
  3. Map2 (Mozilla polyfill)
  4. Array.map
  5. 對於在

觀察

有趣的是,命名函數通常比使用匿名函數快一點(大約 5%)。 但我注意到,polyfill 在 Firefox 中使用命名函數較慢,但在 chrome 中更快,但 chrome 自己的地圖實現在命名函數時較慢......我每個測試了大約 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 映射更慢 - 它被設計為在更大的域上工作,而不是在數組上的簡單 for。

只是想分享一些我認為在這里相關的發現。 我對.map永遠存在一些問題。 切換到哈希映射極大地降低了速度。

我們有一個跨越 200k 個小對象的 map 函數,將該映射轉換為一個散列對象並重新創建數組將其從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])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM