Оптимизация производительности ag-Grid в среде Vue

Оптимизация производительности ag-Grid в среде Vue

1. Проблема обновления данных ag-Grid

В реальных проектах таблицы данных редко предоставляют только функции простого запроса. Особенно в административных системах или рабочих платформах пользователи часто могут непосредственно изменять данные или изменять состояние внутри таблицы.

Например, существует требование, чтобы при нажатии кнопки в определенной ячейке результаты вычислений в других строках немедленно обновлялись, или чтобы пользовательский интерфейс определенной ячейки в реальном времени изменялся в зависимости от глобального состояния на основе Pinia/Vuex.

В проекте для реализации таких функций использовался ag-Grid. ag-Grid предоставляет структуру на основе виртуальной прокрутки и высокопроизводительный движок рендеринга, что делает его очень подходящим для обработки больших объемов данных. Однако в процессе использования совместно с Vue 3 возникли неожиданные проблемы с рендерингом.

- Проблема 1:Проблема с перерисовкой всей таблицы Grid при изменении одной ячейки

При прямом изменении rowData на основе ref или reactive во Vue, Vue обнаруживает изменения в целом массиве. В результате внутри ag-Grid может произойти повторная перерисовка всех строк. Особенно это проявляется, когда данных более тысячи, что вызывает временные задержки в отображении.

- Вопрос 2:Проблема непереноса актуального значения при ссылке на внешнее состояние внутри cellRenderer

В случаях, когда используются внутренние переменные или состояние Pinia, ag-Grid может удерживать значение на момент начальной отрисовки. Это связано с тем, что реактивная система Vue и логика повторного использования компонентов ag-Grid работают по-разному.

- Проблема 3:Избыточный вызов API повторяется при каждом рендеринге

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

2. Причины возникновения проблем с данными

Vue 3 использует систему реактивности на основе Proxy. Хотя это очень эффективная структура в обычных приложениях Vue, могут возникнуть проблемы при использовании с библиотеками, такими как ag-Grid, которые имеют собственный рендеринг движок. ag-Grid управляет следующими состояниями самостоятельно.

  • Строка узла / Состояние ячейки / Состояние прокрутки / Состояние выбора / Состояние транзакции

То есть, как Vue, так и ag-Grid имеют структуру, которая стремится отслеживать состояние и управлять рендерингом. Особенно если rowData отслеживается реактивно на глубоком уровне, Vue будет управлять тысячами объектов данных, обернутых в Proxy. В процессе возникают следующие проблемы.

  1. Увеличение использования памяти

  2. Ненужная отрисовка

  3. Накладные расходы на создание прокси

  4. Увеличение затрат на отслеживание состояния

Кроме того, поскольку ag-Grid использует структуру на основе виртуального прокручивания, оптимизация рендеринга очень важна, и иногда чрезмерное отслеживание реактивности Vue мешало этому. В конечном итоге основная проблема заключалась в том, какие состояния управляются Vue и какие делегируются ag-Grid.

3. Решение

① оптимизация на основе shallowRef

Первый способ решения заключался в объявлении rowData как shallowRef. Ранее для объявления rowData использовались ref или reactive, но в этом случае Vue будет отслеживать все внутренние объекты. В то время как shallowRef не отслеживает изменения свойств внутренних объектов. То есть Vue мог управлять только ссылкой на массив rowData, а фактическое состояние внутри было передано на управление ag-Grid.

image1.png

Таким образом, мы смогли добиться следующего эффекта.

  1. Удаление ненужного отслеживания адаптивности

  2. Снижение полной перерисовки сетки

  3. Снижение использования памяти

  4. Улучшение производительности рендеринга

В частности, в среде Grid с тысячами данных эффект улучшения производительности был очень заметным. Кроме того, структура виртуальной прокрутки также работала значительно стабильнее. Из этого опыта я понял, что не всегда правильно полностью полагаться на реактивную систему Vue для управления состоянием. Иногда делегирование ответственности за управление состоянием библиотеке может быть гораздо более эффективной структурой.

② Пользовательский рендерер ячеек и API транзакций

Вторым решением было использование Пользовательского рендерера ячеек и API транзакций. ag-Grid имеет структуру для повторного использования компонентов ячеек. Это значит, что при прокрутке не создаются заново все компоненты, а переиспользуются существующие компоненты.

image2.png

Проблема в том, что в этом процессе ссылка на внешнее состояние иногда не обновляется до последнего значения. Для решения этой проблемы в проекте был явно реализован метод refresh.

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

  • rowData.value[0].status = ‘Готово’

Но этот подход оказался неэффективной структурой как для Vue, так и для ag-Grid. В конечном итоге структура была изменена на прямое использование API applyTransaction ag-Grid в проекте.

image3.png

Transaction API может явно передавать следующие действия.

  • add / update / remove

Важнейшим преимуществом этой структуры было то, что она позволяет выполнять «частичное обновление». То есть можно обновлять только фактически изменённые строки, не перерисовывая всю сетку. В результате этого можно достичь таких эффектов, как следующие.

  1. Сокращение области рендеринга

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

  3. Увеличение стабильности прокрутки

  4. Снижение вызовов API

  5. Возможность контроля частичного состояния

Особенно в условиях больших данных разница стала очень заметной.

4. Оптимизация производительности и проектирование

Главный урок, который я извлек из этого процесса устранения неполадок, заключается в том, что оптимизация производительности фронтенда — это не просто исправление кода, а «проблема проектирования». Реактивная система Vue очень мощная и удобная.

Однако, когда она комбинируется с библиотеками, такими как ag-Grid, которые имеют собственный движок рендеринга, ответственность за управление состоянием дублируется, что может привести к проблемам с производительностью. В конце концов, важно было задать следующий вопрос.

  • Какое состояние будет управлять Vue?

  • Какое состояние будет делегировано ag-Grid?

  • Насколько далеко будет отслеживаться реактивность?

  • Какие изменения будут обрабатываться как транзакция?

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

5. Заключение

Этот опыт оптимизации производительности ag-Grid был более значимым, чем простое исправление ошибок. Сначала это казалось простой проблемой рендеринга, но на самом деле это была структурная конфликтная проблема между реактивной системой Vue и движком рендеринга ag-Grid. Особенно я смог глубоко прочувствовать следующие элементы.

  • Структура рендеринга больших данных

  • Преимущества и недостатки реактивных систем

  • Управление состоянием на основе транзакций

  • Разделение ролей библиотек и фреймворков

  • Оптимизация виртуального скролла

Прежде всего, я сильно почувствовал важность проектирования, заключающегося в том, что следует доверить фреймворку и что стоит делегировать библиотеке. В заключение, этот опыт был очень значимым, так как он позволил мне глубже понять проектирование производительности и структуры управления состоянием в масштабной фронтенд-среде, выходящей за рамки простого опыта использования Vue или ag-Grid.

<Список литературы>

- официальная документация ag-Grid (https://www.ag-grid.com/vue-data-grid/getting-started/ )

- Официальная документация Vue (https://ko.vuejs.org/api/reactivity-advanced)

люси

Site footer