Производительность Javascript для Array.map

Просто написал несколько тестовых примеров в jsperf, чтобы проверить разницу между именованными и анонимными функциями при использовании Array.map и другие альтернативы.

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

(извините за URL-адрес, нет проверки Array.reduce здесь, я назвал тест, прежде чем полностью решить, что я хочу проверить)

Простой цикл for / while, очевидно, самый быстрый, но я все равно удивлен более чем в 10 раз медленнее Array.map хоть...

Затем я попробовал полифилл от mozilla https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

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)
  4. Array.map
  5. для в

наблюдения

Интересно отметить, что именованные функции обычно работают быстрее, чем если вы используете анонимные функции (около 5%). Но я заметил, что polyfill медленнее с именованными функциями в Firefox, но быстрее в Chrome, но собственная реализация Chrome медленнее с именованными функциями... Я тестировал это примерно в 10 раз каждый, так что даже если это не совсем интенсивное тестирование (которое jsperf уже делает), если моя удача не настолько велика, этого должно быть достаточно в качестве ориентира.

Кроме того, хром map на моей машине эта функция работает в 2 раза медленнее, чем firefox. Не ожидал этого вообще.

И... собственный Firefox Array.map реализация медленнее, чем Mozilla Polyfill... ха-ха

Я не уверен, почему спецификации ECMA-262 утверждают, что map может использоваться для объектов, кроме массивов ( http://www.ecma-international.org/ecma-262/5.1/). Это делает всю функцию карты в 3-4 раза медленнее (как показано в моих тестах), так как вам нужно проверять наличие свойств в каждом цикле...

Заключение

Между именованными и анонимными функциями нет большой разницы, если учесть, что разные браузеры работают немного по-разному.

В конце концов, мы не должны микро-оптимизировать слишком много, но я нашел это интересным:)

2 ответа

Ну, во-первых, это не честное сравнение. Как вы сказали, правильная карта JavaScript может использовать объекты, а не только массивы. Таким образом, вы в основном сравниваете две совершенно разные функции с разными алгоритмами / результатами / внутренней работой.

Конечно, правильная карта javascript медленнее - она ​​разработана для работы над большим доменом, чем простая над массивом.

Просто хочу поделиться некоторыми выводами, которые я считаю уместными здесь. у меня были некоторые проблемы с.mapпринимая навсегда. Переключение на хеш-карту значительно снизило скорость.

У нас была функция карты для 200 тыс. небольших объектов, преобразование этой карты в хешированный объект и воссоздание массива заняло от 20 минут до 0,4 секунды .

Первый подход (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])
Другие вопросы по тегам