Flutter vs. React Native: Analýza výkonnosti

Proč řešit výkon u Flutteru a React Native

Flutter i React Native umožňují doručovat multiplatformní mobilní aplikace s nativním vzhledem a uživatelským zážitkem. Přestože oba přístupy sdílí některé koncepty (hot reload, komponentový model, bohatý ekosystém), zásadně se liší v architektuře vykreslování, běhovém prostředí i způsobu volání nativních API. Cílem tohoto článku je srovnat výkonnostní charakteristiky z hlediska latence vstupu, plynulosti animací, propustnosti uživatelského rozhraní (UI), startovacího času, paměťových nároků, velikosti binárky a nákladů na integraci nativních modulů – a navrhnout praktické optimalizační postupy pro obě technologie.

Architektura vykreslování a její dopad na výkon

  • Flutter: využívá vlastní renderovací engine (Skia, nově Impeller pro Metal/Vulkan), který vykresluje celé uživatelské rozhraní do grafického plátna. Widgety jsou čistě deklarativní, přičemž výsledkem je strom elementů → RenderObject → rasterizace. Díky vlastnímu enginu Flutter obchází nativní widgety operačních systémů a dosahuje konzistentního chování a predikovatelného frame pacingu.
  • React Native: historicky využíval bridge (JavaScript <→ nativní vrstva), který převáděl JSON zprávy mezi světy. Nová architektura (Fabric + JSI + TurboModules) odstraňuje serializaci přes bridge, zrychluje synchronizační body a zlepšuje determinismus. RN renderuje skrze nativní primitiva (UIView/Android View), což přináší lepší adaptaci na platformu, ale větší heterogenitu výkonu.

Startovací čas (cold start) a warm start

  • Flutter: AOT kompilace Dart kódu snižuje interpretativní režii; cold start ovlivňuje inicializace engine a načtení shaderů. Impeller redukuje nutnost kompilace shaderů za běhu (nižší jank při prvních animacích).
  • React Native: s Hermes (optimalizovaný JavaScript engine) a překomilovanými bytykódy klesá inicializační náklad a paměťová spotřeba. Fabric minimalizuje čas potřebný k vytvoření stromu nativních view. Přesto bývá cold start citlivější na velikost bundlu a lazy-loading modulů.

Plynulost UI: FPS, frame pacing a vstupní latence

  • Flutter cílí na 60/120 FPS s oddělením UI a raster threadu; pokud Dart kód blokuje UI thread, animace trpí. Impeller snižuje variance renderu a stabilizuje frame pacing, zejména u složitých shaderů a maskování.
  • React Native: s Fabric/JSI a synchronním layoutem v C++ se snižuje režie při „commit“ fázi. Latence gest výrazně klesá, zejména při použití react-native-reanimated a Gesture Handler, které přesouvají část práce mimo JavaScript event loop.

Animace a gesta

  • Flutter: nabízí bohatý animační systém (tweeny, fyzikální simulace, implicitní/explicitní animace), který běží deterministicky nad DPM (Dart UI). Výkon animací závisí na efektivitě rebuildů a rozumné granularitě widgetů.
  • React Native: Reanimated 2+ umožňuje tzv. worklets přímo na UI threadu; animace tak nemusí čekat na JavaScript. U komplexních scén je výkon srovnatelný s Flutterm, pokud je minimalizován počet re-renderů.

Propustnost layoutu a složitost stromu

  • Flutter: layout probíhá v jednom grafu (měření/layout/paint) mimo nativní hierarchii. Výkon degraduje s hlubokými stromy a častým používáním global keys. RepaintBoundary a AutomaticKeepAlive jsou klíčové pro izolaci a optimalizaci vykreslování.
  • React Native: Fabric používá Yoga (Flexbox). Velmi široké či hluboké stromy mohou způsobit více průchodů layoutem; optimalizace zahrnují memoizaci (React.memo), rozumné zanoření a windowing seznamů.

Grafika, text a rasterizace

  • Flutter: Skia/Impeller poskytují silnou kontrolu nad textem, vektory, klipy, maskami a efekty; cena je větší velikost binárky a nutnost dbát na správu offscreen layers a kompozici.
  • React Native: spoléhá na nativní textové vykreslování a kompozici view, což znamená dobrý výchozí výkon pro standardní UI, ale vyšší náklady na extrémní vizuální efekty (custom canvas → Skia RN, OpenGL nebo platformní kreslení).

Paměťová náročnost a správa paměti (GC)

  • Flutter: Dart používá generational garbage collector, který je rychlý, nicméně vytváření mnoha krátkodobých objektů v horké smyčce (např. v build()) může způsobit mikro-stutter; řešením je recyklace objektů a rozumná granularita widgetů.
  • React Native: Hermes má kompaktní reprezentaci objektů a efektivní garbage collector; je však třeba dávat pozor na úniky paměti způsobené referenčními cykly mezi JavaScriptem a nativními vrstvami a na velké in-memory seznamy bez windowingu.

Velikost binárky (APK/IPA) a doba stahování

  • Flutter: obsahuje engine a Skia/Impeller, což znamená větší základní velikost, zejména u „hello world“ aplikací. Pro produkci je nutné použít R8/ProGuard (Android), bitcode/strip (iOS), asset kompresi a rozdělení balíčků per ABI.
  • React Native: závisí na velikosti JavaScript bundlu a použitých nativních knihovnách; Hermes s bytykódy snižuje runtime náklady a někdy i výslednou velikost.

Volání nativních API a I/O

  • Flutter: využívá platform channels pro binární zprávy; režie je nízká při rozumné granularitě volání. Pro intenzivní streaming bývá vhodné použít event channels nebo FFI s C/C++ knihovnami.
  • React Native: dříve bridge limitoval průchodnost dat, nová architektura JSI/TurboModules odstraňuje serializaci, zlepšuje latenci a umožňuje přímé C++ bindingy. Pro I/O operace je vhodné preferovat pozadí vlákna a řízení backpressure.

Vícevláknové zpracování a paralelismus

  • Flutter: používá Isolates pro CPU-vázanou práci; komunikace probíhá přes porty (bez sdílené paměti). Raster/UI thread jsou oddělené; blokování hlavního isolatu znamená drop frame.
  • React Native: rozdělení na UI thread/render thread/JavaScript thread; nová architektura umožňuje posunout část práce do C++/UI threadu (worklets). Pro těžké výpočty se doporučuje využití nativních modulů.

Seznamy, virtualizace a nekonečné feedy

  • Flutter: využívá ListView.builder, SliverList, SliverGrid a ScrollablePositionedList. Při komplexních položkách je vhodné užívat const widgety, AutomaticKeepAlive a RepaintBoundary.
  • React Native: nabízí FlatList, SectionList s nastavením windowSize, getItemLayout a removeClippedSubviews. Plynulost závisí na správném klíčování, memoizaci item rendereru a stabilních referencích.

Profilování a diagnostika výkonu

  • Flutter: nástroj DevTools (timeline, statistiky rasterizeru, shader warmup), dart:developer (Timeline), flutter run –profile, tracing v Systrace.
  • React Native: nástroje jako Flipper (síť, layout, výkon), Hermes profiler, Systrace/Perfetto, react-devtools a speciální nástroje pro Fabric/JSI.

Energetická efektivita (battery budget)

  • Flutter: stabilní frame pacing snižuje přemalovávání; je však třeba dávat pozor na animace běžící na pozadí, časté volání setState a vysokou frekvenci timerů.
  • React Native: doporučuje minimalizovat zátěž JavaScript event loopu, využívat reanimated worklets a debounce. Preferujte nativní animace a přesun těžkých úloh do nativních modulů.

Modelové benchmarky a interpretace

  • UI microbench: 1) navigace mezi obrazovkami, 2) 10 000 položek ve scrollu, 3) animace 60 fps se stínem a ořezem. Sledujte 95. a 99. percentil frame time, počet ztracených snímků (dropped frames), čas CPU/GPU a pauzy garbage collectoru.
  • Start-up: cold/warm start (Time To Interactive), inicializace modulů a načtení zdrojů. Vyhodnocujte také total blocking time (TBT) na úrovni JavaScriptu/Dartu.
  • I/O a bridge: simulujte 1000 volání nativních API za sekundu; měřte latenci, jitter a využití CPU v obou světech.

Optimalizační postupy pro Flutter

  • Aktivujte Impeller na iOS i Androidu, proveďte shader warmup pro často používané efekty.
  • Rozumně využívejte const konstruktory, ValueListenableBuilder/Selector pro lokální rebuildy a RepaintBoundary u složitých podsestav.
  • Offload CPU-vázané úlohy na Isolates; u streamingového I/O použijte compute() nebo vlastní isolate.
  • Profilujte layout, paint a raster v DevTools a eliminujte nadměrné přemalování (např. pomocí debug repaint rainbow).

Optimalizační postupy pro React Native

  • Přejděte na novou architekturu (Fabric + JSI + TurboModules) a využívejte Hermes.
  • Realizujte animace přes react-native-reanimated a Gesture Handler; minimalizujte závislost na JavaScript event loopu.
  • Memoizujte komponenty (React.memo, useMemo, useCallback), stabilizujte props a klíče.
  • U rozsáhlých seznamů používejte windowing, getItemLayout a removeClippedSubviews.

Velké grafy, mapy a 3D

  • Flutter: pro náročné vizualizace doporučujeme použít CustomPainter, SceneBuilder a případně FFI (C/C++). Mapy: preferujte nativní integrace s platformními SDK přes platform channels.
  • React Native: pro graficky náročné scény lze využít react-native-skia nebo WebGL/Vulkan bindingy; mapy implementujte přes nativní SDK s minimalizací prop-drillingu.

Stabilita frame pacingu vs. nativní vzhled

Flutter díky vlastnímu enginu nabízí velmi stabilní a konzistentní frame pacing napříč zařízeními; naopak cena je větší velikost balíčku a někdy méně „zcela nativní“ pocit u některých komponent (to je řešitelné knihovnami Material, Cupertino a třetích stran). React Native těží z nativních komponent a přirozených interakcí operačního systému, avšak u heterogenních zařízení vyžaduje více péče o ladění výkonu (zejména z minulosti s bridgem; Fabric však většinu omezení výrazně zmírňuje).

Bezpečnost a sandbox výkonu

  • Flutter: FFI zvyšuje výkon tam, kde je potřebná nativní knihovna; je nutné dbát na thread safety a životní cyklus engine.
  • React Native: JSI C++ moduly umožňují psát vysoce výkonný kód blízko hardwaru; důležité je zajistit správnou správu paměti a kompatibilitu mezi platformami.

Jak vybrat technologii z pohledu výkonu

  • Hodně animací, custom UI, konzistence na široké škále hardwaru: Flutter má výhodu díky vlastnímu renderingu a Impelleru.
  • Silná integrace s nativními view a knihovnami, „platform-first“ UX: React Native s Fabric a Hermes je ideální volba, obzvlášť při využití reanimated.
  • Těžké výpočty: obě technologie vyžadují přesun do nativních modulů či izolátů; rozdíly ve výkonu více závisí na kvalitě implementace než na frameworku.

Antipatterny a časté chyby

  • Flutter: masivní rebuildy stromu způsobené změnami v nadřazených InheritedWidget; absence RepaintBoundary; synchronní I/O na UI isolatu; nadměrné používání GlobalKey.
  • React Native: časté volání setState bez memoizace; těžké operace na JavaScript threadu; velké JS bundle bez kódového dělení; spoléhání na starý bridge při vysoké frekvenci volání.

Roadmapa a budoucí směry

  • Flutter: další zlepšování Impelleru, redukce janku v první fázi běhu, optimalizace pro 120 Hz displeje a lepší interoperabilita s nativními poh