DevGang
Авторизоваться

React vs. Vanilla: Сколько ресурсов потребляет один клик?

React, как и любой другой JavaScript-фреймворк, выполняет множество скрытых задач, о которых мы, разработчики, не задумываемся. Это нормальная практика: мы фокусируемся на решении проблем, и чем проще реализация, тем лучше. Однако важно понимать, что даже если мы не всегда вникаем в детали работы фреймворка, он все равно оказывает влияние на производительность приложения.

JavaScript по-прежнему остается ведущим языком веб-разработки, и вряд ли в ближайшем будущем уступит свои позиции. Более того, многие нативные приложения (iOS, Android, Smart TV) используют гибридные решения, сочетающие нативную разработку с веб-технологиями.

В этой статье мы сравним производительность простого счетчика, реализованного на React, с его ванильной JavaScript-версией. 

Инструменты

Для измерения производительности мы будем использовать вкладку Chrome DevTools "Performance". Она позволяет записывать и анализировать работу веб-приложения, предоставляя информацию по следующим ключевым показателям:

  • JS Heap: Область памяти, где хранятся объекты, массивы и функции в JavaScript.
  • DOM Nodes: Отдельные элементы, атрибуты или текст в HTML-коде, представленные в DOM.
  • Прослушиватели событий: Функции, реагирующие на определенные события, такие как щелчки мыши или нажатия клавиш.

Демонстрация создание простого счетчика React

В качестве примера возьмем простой счетчик. Он будет состоять из кнопки с обработчиком клика, который увеличивает значение счетчика при каждом нажатии. 

Сравнение:

Далее мы сравним результаты работы счетчика на React и Ванильном JavaScript, анализируя изменения в heap JS, количестве узлов DOM и прослушивателей событий при каждом клике.

Код React выглядит следующим образом:

"use client";

import { useState } from "react";

export default function Page() {
  const [counter, setCounter] = useState(0);

  const incrementClickHandler = (event: { preventDefault: () => void }) => {
    event.preventDefault();

    setCounter((prevCounter) => prevCounter + 1);
  };

  return (
    <div style={{ maxWidth: 800, margin: "0 auto" }}>
      <a
        href="#"
        style={{
          display: "inline-block",
          padding: "20px 40px",
          fontSize: 28,
          border: "1px solid black",
          width: "100%",
          textAlign: "center",
          marginTop: 40,
        }}
        onClick={incrementClickHandler}
      >
        Increment {counter}
      </a>
    </div>
  );
}

Код довольно понятен. Следует отметить, что демонстрация выполняется поверх Next.js, поэтому нам нужен use client. В остальном это всего лишь базовый компонент React.

Пользовательский интерфейс React Counter

20 секунд и всего один щелчок мышью

Теперь я собираюсь открыть вкладку "Производительность" в Chrome, щелкнуть значок записи и дать ей поработать в течение 20 секунд, нажав на кнопку только один раз. По истечении 20 секунд результаты работы будут выглядеть следующим образом:

Посмотрите, как всего одним щелчком мыши цифры увеличиваются до:

React
JS Heap 3.4MB
Nodes 47
Listeners 287

20 секунд с одним щелчком в секунду

Теперь я собираюсь дать ему поработать еще 20 секунд, но на этот раз я буду нажимать на кнопку раз в секунду. Давайте посмотрим на результаты:

React
JS Heap 4MB
Nodes 46
Listeners 331

В React следует отметить две вещи:

  1. При обновлении переменной состояния компонент отрисовывается повторно, что означает, что в данном случае компонент отрисовывался 20 раз.
  2. Благодаря виртуальной DOM, React обновляет только те узлы, которые необходимо обновить.

Теперь давайте вернемся к графику и посмотрим, как увеличиваются синяя линия (Heap JS) и желтая линия (слушатели), в то время как зеленая линия (узлы) остается неизменной.

Также стоит отметить, что цифры не сильно изменились по сравнению с запуском в один клик.

Демонстрация: Создание счетчика Vanilla JavaScript

Теперь у нас тот же пользовательский интерфейс, но на этот раз он построен с использованием простых HTML и JavaScript — без использования фреймворков.

<html>
  <head>
    <script>
      let increment = 0;

      window.onload = function () {
        document.querySelector("#counter").innerText = increment;

        document.querySelector("a").addEventListener("click", function (event) {
          event.preventDefault();
          increment++;
          document.querySelector("#counter").innerText = increment;
        });
      };
    </script>
  </head>
  <body style="max-width: 800; margin: 0 auto; font-family: monospace;">
    <a
      href="#"
      style="
        display: inline-block;
        padding: 20px 40px;
        font-size: 28px;
        border: 1px solid black;
        width: 100%;
        text-align: center;
        text-decoration: none;
        color: black;
        margin-top: 40;
        box-sizing: border-box;
      "
      >Increment <span id="counter"></span>
    </a>
  </body>
</html>

Следует упомянуть необходимость следующего элемента:

<span id="counter"></span>

который обрабатывается с помощью JavaScript для обновления его содержимого:

document.querySelector("#counter").innerText = increment;

Интерфейс счетчика Vanilla

20 секунд и всего один клик

Я снова щелкну по значку записи и оставлю запись на 20 секунд, нажав на кнопку только один раз.

Взгляните на результаты:

Vanilla
JS Heap 1.7MB
Nodes 16
Listeners 20

20 секунд, по одному щелчку в секунду

Я снова собираюсь щелкнуть значок записи и дать ей поработать еще 20 секунд, но на этот раз я буду нажимать на кнопку раз в секунду. Ознакомьтесь с результатами:

Vanilla
JS Heap 2.3MB
Nodes 42
Listeners 77

Как и в примере с React, потребление памяти (синяя линия) и количество слушателей событий (желтая линия) постепенно увеличивались. Количество узлов DOM (зеленая линия) оставалось стабильным, но каждый клик вызывал кратковременный рост, после чего оно возвращалось к исходному значению. 

Сборка мусора: невидимый помощник

Сборка мусора — это процесс автоматического освобождения ресурсов, которые больше не используются. JavaScript выполняет сборку мусора автоматически, нам не нужно вмешиваться. В наших примерах мы видели, как ресурсы потребляются, но в определенный момент JavaScript сам высвобождает некоторые из них с помощью сборщика мусора.

Выводы

Независимо от количества кликов (1 или 20), потребление ресурсов незначительно отличается. JavaScript выделяет ресурсы при первом клике, и последующие клики лишь увеличивают это потребление. Однако скачок между нулевым и первым кликом более заметен, чем между последующими.

Ниже представлены конечные значения потребления ресурсов для 20 кликов в обеих версиях:

Vanilla React
JS Heap 2.3MB 4.0MB
Nodes 42 46
Listeners 77 331

Понятно, что React потребляет больше ресурсов, так как это неизбежная плата за использование фреймворка.

Ключевое различие заключается в том, что React добавляет все узлы DOM сразу, в то время как ванильная версия добавляет их по мере кликов. Тем не менее, в конечном итоге обе версии имеют примерно одинаковое количество узлов DOM.

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

Источник:

#JavaScript #React
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу