Оценка производительности среды выполнения небольшой программы

Апплет WeChat внешний фреймворк

Автор: Донг Хунпин (Хиюки), руководитель мини-программы Didi Chuxing, глава mpx framework и основной автор

Благодаря большому коммерческому успеху небольших программ разработка небольших программ получает все больше и больше внимания в отечественной области переднего плана.Чтобы облегчить разработчикам лучшую разработку небольших программ, одна за другой появлялись различные фреймворки для небольших программ, показывая тенденцию цветущих цветов. Однако до сих пор не было всеобъемлющего, подробного, объективного и справедливого отчета об оценке структуры апплета, который мог бы служить ориентиром для разработчиков апплета при выборе технологии. Поэтому я планировал запустить серию статей, чтобы провести всестороннюю, объективную и справедливую оценку популярных в отрасли фреймворков апплетов.Эта статья является первой из серии статей — производительность во время выполнения.

В этой статье мы проводим тесты производительности во время выполнения на следующих платформах (в произвольном порядке):

Среди них и kbone, и taro next тестируются с vue в качестве бизнес-фреймворка.

Тестовое содержание производительности среды выполнения включает следующие измерения:

  • Объем среды выполнения фреймворка
  • Время рендеринга страницы
  • Время обновления страницы
  • Частичное обновление, занимающее много времени
  • Количество вызовов setData
  • setData размер передаваемых данных

Все демонстрационные тесты производительности фреймворка хранятся вGitHub.com/Hi Yuki/Tickets — Отправить…, разработчики могут проверять, исправлять и дополнять;

Тестовая программа

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

Сценарий динамического тестирования

В динамическом тесте представление динамически рендерится на основе данных, статических узлов мало, обновление представления отнимает много времени, а вызов setData является основной контрольной точкой в ​​тестовой сцене.

Динамическая тестовая демонстрация имитирует обычный сценарий с длинным списком и несколькими вкладками в реальном бизнесе. В демонстрации есть два списка данных купона, один из которых является доступным купоном, а другой — недоступным купоном. Один из данных будет отображаться и отображается, а различные операции с данными списка и переключением отображения представления (вкладка выреза) могут быть смоделированы в верхней рабочей области.

Динамическая тестовая демонстрация

В динамическом тесте я проксирую конструкторы App, Page и Component перед инициализацией с помощью функционального прокси и внедряю логику перехвата setData в созданные хуки onLoad и Component с помощью миксинов.Вызов setData компонента отслеживается, и учитывается время обновления представления и вызов setData апплета. Этот тестовый метод позволяет добиться нулевого вторжения в код фреймворка, может отслеживать полное поведение setData апплета и выполнять независимые трудоемкие вычисления, а также обладает сильной универсальностью Конкретную реализацию кода можно просмотретьGitHub.com/Hi Yuki/Tickets — Отправить…

Сценарий статического тестирования

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

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

демонстрация статического теста

Процесс тестирования и данные

Все трудоемкие тестовые данные, приведенные ниже, рассчитываются из среднего значения 5 тестов, выполненных на реальной машине в апплете WeChat, и единицей измерения является мс. Тестовая среда iOS — модель мобильного телефона iPhone 11, версия системы — 13.3.1 и версия WeChat 7.0.12, тестовая среда Android — модель мобильного телефона Xiaomi 9, версия системы — Android 10, а WeChat версия 7.0.12.

Чтобы сделать отображение данных не слишком хаотичным и сложным, данные, перечисленные в статье, в основном основаны на результатах тестирования iOS.Вывод теста Android соответствует Ios, а общее время примерно в 3-4 раза выше, чем Ios. Все исходные тестовые данные хранятся вGitHub.com/Hi Yuki/Tickets — Отправить…

Поскольку ядро-js, представленное средой выполнения преобразования, будет иметь определенное влияние на объем среды выполнения и время работы фреймворка, и не все фреймворки будут включать время выполнения преобразования во время компиляции.Чтобы согласовать тестовую среду, следующие тесты выполняются в режиме преобразования — время выполнения отключено.

Объем среды выполнения фреймворка

Так как не все фреймворки можно использоватьwebpack-bundle-analyzerЧтобы получить точную занятость объема пакета, здесь я использую объем демо-проекта, сгенерированный каждой структурой, за вычетом объема демо-проекта, написанного нативным, в качестве объема среды выполнения фреймворка.

Общий объем демо (КБ) Объем среды выполнения фреймворка (КБ)
native 27 0
wepy2 66 39
uniapp 114 87
mpx 78 51
chameleon 136 109
mpvue 103 76
kbone 395 368
taro next 183 156

Тест пришел к выводу, что:
native > wepy2 > mpx > mpvue > uniapp > chameleon > taro next > kbone

Заключение анализа:

  • wepy2 и mpx имеют лучший контроль над объемом среды выполнения фреймворка;
  • Из-за особенностей динамического рендеринга taro next и kbone будут генерировать шаблоны/компоненты рекурсивного рендеринга в dist, поэтому они занимают большой объем.

Время рендеринга страницы (динамический тест)

Мы используем刷新页面Операция запускает перезагрузку страницы.Для большинства фреймворков время рендеринга страницы — это время от запуска операции обновления до выполнения страницы onReady, но для динамических фреймворков рендеринга, таких как kbone и taro next, страница, выполняющаяся onReady, не представляет представление. Реальный рендеринг завершен, для этого мы устанавливаем специальное правило: в течение 1000 мс после срабатывания страницы onReady, когда callback setData происходит без каких-либо операций, последний сработавший callback setData используется как время завершения рендеринга страницы для расчета реального Рендеринг страницы требует времени, и результаты тестов таковы:

Время рендеринга страницы
native 60.8
wepy2 64
uniapp 56.4
mpx 52.6
chameleon 56.4
mpvue 117.8
kbone 98.6
taro next 89.6

Время, отнимающее этот тест, не совпадает с реальным временем рендеринга.Поскольку сам апплет не обеспечивает производительность API, реальное время рендеринга не может быть точно протестировано с помощью js, но данные все еще имеют определенную ссылку.

Тест пришел к выводу, что:
mpx ≈ хамелеон ≈ uniapp ≈ натив ≈ wepy2 > таро некст ≈ kbone ≈ mpvue

Заключение анализа:

  • Поскольку mpvue полностью рендерится на странице, kbone и taro далее используют технологию динамического рендеринга, рендеринг страницы занимает много времени, а в остальном фреймворк мало чем отличается.

Длительное обновление страницы (без фоновых данных)

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

Метод расчета времени обновления — это время от срабатывания события операции с данными до завершения соответствующего обратного вызова setData.

В mpvue текущая метка времени (новая дата) используется в качестве основы тайм-аута для выполнения операции регулирования с тайм-аутом 50 мс на setData.У этого метода есть серьезные проблемы.Когда выполнение одного процесса синхронизации рендеринга в vue занимает более 50 мс , последующие компоненты setData, запускаемые патчем, преодолеют этот предел регулирования и будут делать высокочастотные недействительные вызовы setData с частотой 50 мс каждый раз. В этой демонстрации производительности, когда количество купонов превышает 500, интерфейс полностью зависает. Чтобы весь тестовый процесс прошел гладко, я сделал простое исправление проблемы и использовал setTimeout, чтобы переписать регулирующую часть, чтобы убедиться, что setData будет вызываться для отправки объединенных данных после синхронного выполнения одного процесса рендеринга vue, а затем все тесты производительности mpvue основаны на этой версии патча, которая хранится по адресу https://github.com/hiyuki/mp-framework-benchmark/blob/master/frameworks/mpvue/runtime/patch/index.js

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

Для первого теста мы используем新增可用券(100)Операция постепенно увеличивает количество доступных купонов от 0 до 1000:

100 200 300 400 500 600 700 800 900 1000
native 84.6 69.8 71.6 75 77.2 78.8 82.8 93.2 93.4 105.4
wepy2 118.4 168.6 204.6 246.4 288.6 347.8 389.2 434.2 496 539
uniapp 121.2 100 96 98.2 97.8 99.6 104 102.4 109.4 107.6
mpx 110.4 87.2 82.2 83 80.6 79.6 86.6 90.6 89.2 96.4
chameleon 116.8 115.4 117 119.6 122 125.2 133.8 133.2 144.8 145.6
mpvue 112.8 121.2 140 169 198.8 234.2 278.8 318.4 361.4 408.2
kbone 556.4 762.4 991.6 1220.6 1468.8 1689.6 1933.2 2150.4 2389 2620.6
taro next 470 604.6 759.6 902.4 1056.2 1228 1393.4 1536.2 1707.8 1867.2

Затем мы щелкаем по пунктам по порядку删除可用券(all) > 新增可用券(1000) > 更新可用券(1) > 更新可用券(all) > 删除可用券(1):

delete(all) add(1000) update(1) update(all) delete(1)
native 32.8 295.6 92.2 92.2 83
wepy2 56.8 726.4 49.2 535 530.8
uniapp 43.6 584.4 54.8 144.8 131.2
mpx 41.8 489.6 52.6 169.4 165.6
chameleon 39 765.6 95.6 237.8 144.8
mpvue 103.6 669.4 404.4 414.8 433.6
kbone 120.2 4978 2356.4 2419.4 2357
taro next 126.6 3930.6 1607.8 1788.6 2318.2

На ранней стадии этого теста логика моего update(all) заключается в циклическом обновлении каждого элемента списка в видеlistData.forEach((item)=>{item.count++}), обнаружено, что интерфейс выполнения в фреймворке хамелеон будет полностью зависать, а отслеживание обнаружило, что setData не асинхронно сливается в фреймворке хамелеон, а напрямую синхронно отправляется при изменении данных, так что объем данных составляет 1000 , Он будет запускать setData 1000 раз с высокой частотой, вызывая зависание интерфейса; для этого в тестовой демонстрации фреймворка хамелеон я скорректировал логику update(all) для глубокого клонирования для создания обновленного listData, а затем назначил его в целом в this.listData, чтобы убедиться, что тест может быть выполнен нормально.

Тест пришел к выводу, что:
родной > mpx ≈ uniapp > хамелеон > mpvue > wepy2 > таро далее > kbone

Заключение анализа:

  • mpx и uniapp провели идеальную дифф оптимизацию внутри фреймворка, с увеличением объема данных время добавления двух фреймворков существенно не увеличивается;
  • wepy2 также будет устанавливать Data в данные реквизита, когда данные изменяются, что приводит к значительной потере производительности в этом сценарии, что приводит к снижению производительности;
  • Затем kbone и taro используют схему динамического рендеринга, и каждый раз, когда добавляется новое обновление, будет отправлено большое количество данных, описывающих структуру dom.В то же время динамическая рекурсивная визуализация занимает гораздо больше времени, чем обычного статического рендеринга шаблонов, что делает эти две платформы во всех сценариях обновления, отнимающих много времени, намного длиннее, чем в других платформах.

Длительное обновление страницы (с фоновыми данными)

После обновления страницы используем新增不可用券(1000)Создайте фоновые данные, посмотрите, вызовет ли операция setData и подсчитайте время

back add(1000)
native 45.2
wepy2 174.6
uniapp 89.4
mpx 0
chameleon 142.6
mpvue 134
kbone 0
taro next 0

Когда mpx выполняет оптимизацию setData, вдохновленную vue, функция рендеринга, сгенерированная во время компиляции, используется для отслеживания зависимостей данных шаблона, а setData не будет вызываться при изменении фоновых данных, в то время как kbone и taro затем используют технологию динамического рендеринга для имитации базовой сети. Верхний слой полностью запускает фреймворк vue и достигает того же эффекта.

Затем мы выполняем ту же операцию, что и выше, без фоновых данных для трудоемкой статистики, сначала увеличивая на 100:

100 200 300 400 500 600 700 800 900 1000
native 88 69.8 71.2 80.8 79.4 84.4 89.8 93.2 99.6 108
wepy2 121 173.4 213.6 250 298 345.6 383 434.8 476.8 535.6
uniapp 135.4 112.4 110.6 106.4 109.6 107.2 114.4 116 118.8 117.4
mpx 112.6 86.2 84.6 86.8 90 87.2 91.2 88.8 92.4 93.4
chameleon 178.4 178.2 186.4 184.6 192.6 203.8 210 217.6 232.6 236.8
mpvue 139 151 173.4 194 231.4 258.8 303.4 340.4 384.6 429.4
kbone 559.8 746.6 980.6 1226.8 1450.6 1705.4 1927.2 2154.8 2367.8 2617
taro next 482.6 626.2 755 909.6 1085 1233.2 1384 1568.6 1740.6 1883.8

Затем нажмите статистику один за другим в соответствии с последовательностью операций таблицы.

delete(all) add(1000) update(1) update(all) delete(1)
native 43.4 299.8 89.2 89 87.2
wepy2 43.2 762.4 50 533 522.4
uniapp 57.8 589.8 62.6 160.6 154.4
mpx 45.8 490.8 52.8 167 166
chameleon 93.8 837 184.6 318 220.8
mpvue 124.8 696.2 423.4 419 430.6
kbone 121.4 4978.2 2331.2 2448.4 2348
taro next 129.8 3947.2 1610.4 1813.8 2290.2

Тест пришел к выводу, что:
native > mpx > uniapp > chameleon > mpvue > wepy2 > taro next > kbone

Заключение анализа:

  • Три фреймворка mpx, kbone и taro next с возможностью отслеживания данных шаблона не увеличивают значительно времязатраты в сценариях с фоновыми данными;
  • Точность diff в wepy2 недостаточна, а затраты времени существенно не изменились;
  • У остальных фреймворков есть определенное улучшение по времени, потому что каждое обновление будет выполнять глубокое сравнение фоновых данных.

Длительное обновление страницы (сценарий большого объема данных)

Так как рендеринг mpvue и taro next выполняется на странице, а схема рендеринга kbone добавит большое количество дополнительных пользовательских компонентов, эти три фреймворка вылетят и появятся белые экраны, когда количество купонов достигнет 2000, мы исключили эти три. Framework выполняет трудоемкое тестирование обновлений страниц в сценариях с большим объемом данных для других фреймворков.

Во-первых, он по-прежнему используется в сценариях без фоновых данных.新增可用券(1000)Увеличьте количество доступных купонов до 5000:

1000 2000 3000 4000 5000
native 332.6 350 412.6 498.2 569.4
wepy2 970.2 1531.4 2015.2 2890.6 3364.2
uniapp 655.2 593.4 655 675.6 718.8
mpx 532.2 496 548.6 564 601.8
chameleon 805.4 839.6 952.8 1086.6 1291.8

затем нажмите新增不可用券(5000)Увеличьте объем фоновых данных до 5000, а затем проверьте время, необходимое для увеличения количества доступных купонов до 5000:

back add(5000)
native 117.4
wepy2 511.6
uniapp 285
mpx 0
chameleon 824
1000 2000 3000 4000 5000
native 349.8 348.4 430.4 497 594.8
wepy2 1128 1872 2470.4 3263.4 4075.8
uniapp 715 666.8 709.2 755.6 810.2
mpx 538.8 501.8 562.6 573.6 595.2
chameleon 1509.2 1672.4 1951.8 2232.4 2586.2

Тест пришел к выводу, что:
native > mpx > uniapp > chameleon > wepy2

Заключение анализа:

  • В сценарии с большим объемом данных разница в базовой производительности между фреймворками станет более очевидной, mpx и uniapp по-прежнему сохраняют хорошую производительность, близкую к оригиналу, а chameleon и wepy2 имеют относительно значительное снижение производительности.

Частичное обновление, занимающее много времени

Когда количество доступных купонов равно 1000, щелкните любой из доступных купонов, чтобы активировать выбранное состояние для проверки производительности частичного обновления.

toggleSelect(ms)
native 2
wepy2 2.6
uniapp 2.8
mpx 2.2
chameleon 2
mpvue 289.6
kbone 2440.8
taro next 1975

Тест пришел к выводу, что:
натив ≈ хамелеон ≈ mpx ≈ wepy2 ≈ uniapp > mpvue > таро далее > kbone

Заключение анализа:

  • Можно видеть, что все фреймворки, использующие собственные пользовательские компоненты для компонентной реализации, требуют очень мало времени для локального обновления, чего достаточно, чтобы доказать превосходство и важность собственных пользовательских компонентов апплета;
  • За счет использования обновлений страниц в mpvue значительно увеличивается время локального обновления;
  • Из-за огромных накладных расходов на рекурсивную динамическую отрисовку в kbone и taro next время локального обновления также огромно.

вызов setData

мы будемproxySetDataУстановите для параметров count и size значение true, включите статистику количества и объема setData, выполните ряд операций в соответствии со следующим процессом после перестроения и подсчитайте количество вызовов setData и объем отправленных данных.

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

  1. Доступно 100 купонов шаг за шагом (0-> 500)
  2. Переключиться на недоступный купон
  3. Добавлен недоступный купон (1000)
  4. Доступно 100 купонов шаг за шагом (500->1000)
  5. Обновить доступные купоны (все)
  6. перейти к доступным купонам

После завершения операции используемgetCountа такжеgetSizeМетод получает накопленное количество вызовов setData и объем данных, где метод расчета объема данных — JSON.stringify, а затем вычисляет объем в соответствии с методом кодирования utf-8.Статистические результаты:

count size(KB)
native 14 803
wepy2 3514 1124
mpvue 16 2127
uniapp 14 274
mpx 8 261
chameleon 2515 319
kbone 22 10572
taro next 9 2321

Тест пришел к выводу, что:
mpx > uniapp > native > chameleon > wepy2 > taro next > mpvue > kbone

Заключение анализа:

  • Фреймворк mpx успешно достигает оптимального setData в теории;
  • uniapp немного отстает из-за отсутствия возможностей отслеживания шаблонов;
  • Поскольку хамелеон выполняет ненужный setData каждый раз при создании компонента, генерируется большое количество недопустимых вызовов setData, но сама передача данных отличается, и она хорошо работает с объемом отправляемых данных;
  • Компоненты wepy2 будут вызывать setData для отправки обновленных данных реквизита при обновлении данных, поэтому также генерируется большое количество недопустимых вызовов, а точность diff недостаточна, а количество отправляемых данных также велико;
  • Поскольку верхний уровень полностью основан на Vue, таро затем контролирует количество передач данных до 9 раз, но поскольку необходимо отправить большой объем информации описания DOM, объем передачи данных велик;
  • Поскольку mpvue использует длинный путь данных для описания компонентов, соответствующих данным, он также генерирует большой объем передаваемых данных;
  • Kbone не очень хорошо контролирует вызов setData, в случае запуска vue на верхнем уровне по-прежнему выполняется 22 передачи данных, и объем отправляемых данных огромен, достигая в этом процессе поразительных 10 МБ.

Время рендеринга страницы (статический тест)

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

Время рендеринга страницы
native 70.4
wepy2 86.6
mpvue 115.2
uniapp 69.6
mpx 66.6
chameleon 65
kbone 144.2
taro next 119.8

Тест пришел к выводу, что:
хамелеон ≈ mpx ≈ uniapp ≈ родной > wepy2 > mpvue ≈ таро next > kbone

Заключение анализа:

  • За исключением того, что kbone и taro далее используют динамический рендеринг, производительность рендеринга mpvue немного хуже, а производительность рендеринга статических страниц других фреймворков аналогична производительности нативных.

В заключение

Объединив приведенные выше тестовые данные, мы получаем окончательный рейтинг производительности среды выполнения апплета следующим образом:
mpx > uniapp > chameleon > wepy2 > mpvue > taro next > kbone

немного личного

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

Фреймворк mpx, разработку которого я возглавляю (github.com/didi/mpx) выбрал другой способ решения проблемы юзабилити, а именно улучшить собственные грамматические возможности апплета, что позволяет не только избежать неопределенности и нестабильности, вызванных переводом веб-фреймворка, но и максимально приблизить его к нативному. настоятельно рекомендуется разработчикам сложных бизнес-приложений. С точки зрения кросс-конечного вывода, mpx в настоящее время может полностью поддерживать изоморфный вывод всех платформ апплетов и веб-платформ в отрасли.Самый важный и сложный апплет в Didi, апплет Didi Chuxing, полностью разработан на основе mpx и использует framework Предоставленная кросс-конечная возможность обеспечивает синхронную бизнес-итерацию на порталах WeChat и Alipay, что значительно повышает эффективность развития бизнеса.