Как ускорить оператор spread в JavaScript

  • 23 декабря, 16:28
  • 4574
  • 0

Прежде чем мы узнаем, как улучшить производительность spread-оператора в JavaScript, заглянем под капот работы с итерированными объектами самого оператора.

Оператор spread, или многоточие, работает с массивами или вообще с итерированными объектами и разделяет их на элементы, из которых формируется новый массив.Таким образом, оператор ..., используемый перед массивом, или любой другой коллекцией значений (строки, объекты), называет spread

Spread-оператор может стоять на любой позиции внутри литерала массива:

const numbers = [1, 2, 3];
[0, ...numbers];    // => [0, 1, 2, 3]
[0, ...numbers, 4]; // => [0, 1, 2, 3, 4]
[...numbers, 4];    // => [1, 2, 3, 4]

А теперь интересный вопрос: зависит производительность кода от расположения spread-оператора в массиве? Узнаем!

1. Создаем вспомогательные функции

Перед тем как начнем сравнения производительности, объявим две функции. Первая из них - appendToTail():

function appendToTail(item, array) {
  return [...array, item];
}

const numbers = [1, 2, 3];
appendToTail(10, numbers); // => [1, 2, 3, 10]

Суть созданной функции в том, что она вставляет числа в конец массива. Для этого мы используем конструкцию [...array, item].

Следующая функция appendToHead():

function appendToHead(item, array) {
  return [item, ...array];
}

const numbers = [1, 2, 3];
appendToHead(10, numbers); // => [10, 1, 2, 3]

appendToHead()- чистая функция, которая возвращает новый массив, где элементы добавляются в начало. Для этого используем конструкцию [item, ...array].

Вам может показаться, что нет никакой разницы в производительности этих функций. Но ...

2. Тест производительности

Протестуем скорость конструкций [...array, item]vs [item, ...array] на MacBook Pro в таких браузерах:

  • Chrome 76
  • Firefox 68
  • Safari 12.1

Результаты проверки:

Как ускорить оператор spread в JavaScript

Видим, что в браузерах Firefox и Safari оба варианта имеют примерно одинаковую производительность.

А вот в Chrome конструкция [...array, item] отрабатывает вдвое быстрее, чем [item, ...array].

Поэтому, чтобы ускорить производительность spread-оператора в Chrome, используйте его в начале литерал массива:

const result = [...array, item];

Возникает вопрос: почему так происходит?

3. Fast-path оптимизация

Начиная с версии 7.2, двигатель V8, который отвечает за выполнение JavaScript в Chrome, поддерживает оптимизацию spread-оператора: fast-path оптимизацию .

Кратко поясним принцип ее работы.

Без оптимизации, когда двигатель наталкивается на оператор spread, вызывается метод итератора iterator.next() для итерированных объектов. На каждой итерации память конечного массива увеличивается и добавляется новый элемент.

Однако с fast-path оптимизацией мы избегаем создания объекта итератора вообще. Двигатель определяет длину расширенного массива и выделяет память только раз для конечного массива. Далее каждый элемент расширенного массива добавляется в конечный. Таким образом и увеличивается производительность.

4. Поддерживаемые структуры данных

Fast-path оптимизация применяется к таким структурам данных в JavaScript:

массивы

const numbers = [1, 2, 3, 4];

[...numbers, 5]; // => [1, 2, 3, 4, 5]

строки

const message = 'Hi';

[...message, '!']; // => ['H', 'i', '!']

сети

const colors = new Set(['blue', 'white']);

[...colors, 'green'];          // => ['blue', 'white', 'green']
[...colors.values(), 'green']; // => ['blue', 'white', 'green']
[...colors.keys(), 'green'];   // => ['blue', 'white', 'green']

Map

Поддерживается только для методов map.keys()и map.values():

const names = new Map([[5, 'five'], [7, 'seven']]);

[...names.values(), 'ten']; // => ['five', 'seven', 'ten']
[...names.keys(), 10];      // => [5, 7, 10]

Вывод

Когда мы используем оператор spread в начале массива, производительность кода увеличивается благодаря fast-path оптимизации. Она доступна в двигатели V8 с версии 7.2 (представлено в Chrome v72и NodeJS v12).

Тесты производительности показывают, что можно достичь двойного ускорения, если использовать конструкцию [...array, item], а не [item, ...array].

Конечно, fast-path - полезная вещь, однако стоит обращать на это внимание только при работе с большими массивами, когда производительность действительно очень важна.

Источник


0 комментариев
Сортировка:
Добавить комментарий