Автор: Донг Хунпин (Хиюки), руководитель мини-программы Didi Chuxing, глава mpx framework и основной автор
Благодаря большому коммерческому успеху небольших программ разработка небольших программ получает все больше и больше внимания в отечественной области переднего плана.Чтобы облегчить разработчикам лучшую разработку небольших программ, одна за другой появлялись различные фреймворки для небольших программ, показывая тенденцию цветущих цветов. Однако до сих пор не было всеобъемлющего, подробного, объективного и справедливого отчета об оценке структуры апплета, который мог бы служить ориентиром для разработчиков апплета при выборе технологии. Поэтому я планировал запустить серию статей, чтобы провести всестороннюю, объективную и справедливую оценку популярных в отрасли фреймворков апплетов.Эта статья является первой из серии статей — производительность во время выполнения.
В этой статье мы проводим тесты производительности во время выполнения на следующих платформах (в произвольном порядке):
- wepy2(GitHub.com/Tencent/WEP…) @2.0.0-alpha.20
- uniapp(GitHub.com/Открыто много раз/UN…) @2.0.0-26120200226001
- mpx(github.com/didi/mpx) @2.5.3
- chameleon(GitHub.com/Brother/Что за чай...) @1.0.5
- mpvue(GitHub.com/Mehtuan-DI Ах…) @2.0.6
- kbone(GitHub.com/Tencent/Quickcast…) @0.8.3
- taro next(github.com/NervJS/taro) @3.0.0-alpha.5
Среди них и 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 и объем отправленных данных.
Процесс операции выглядит следующим образом:
- Доступно 100 купонов шаг за шагом (0-> 500)
- Переключиться на недоступный купон
- Добавлен недоступный купон (1000)
- Доступно 100 купонов шаг за шагом (500->1000)
- Обновить доступные купоны (все)
- перейти к доступным купонам
После завершения операции используем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, что значительно повышает эффективность развития бизнеса.