Галоўная / Артыкулы

Што оптымізуе компіляр React і шта застаёцца на вашай адпаведнасці

З’ясавайце, які аспекты працэйнасупрацоўкі автаматызуе React Compiler, чаму спадзялыя API і важкія пакеты застаюцца вашай адпаведнасцю, і як безпечна ўжываць яго ў уже існуючай базе коду React.

Выдавец: REACTAPP.TOP6 хв чытання1421 слоў

Крыніцы: React Compiler Won’t Fix a Slow React App

Кампайляр React абсалютна большая частка ручнай мемаізацыі, што стварае прагненне спрытваць яго як рашэння проблемы медленных дапрацоўкаў. Аднак гэта не так: ён оптымізуе толькі процес атрыбутавання, які контролюеўць React, і нічога больш. Чырвоным паказана, дзе знаходзіцца гэтыя межы, якія спамеджэнняя ўсё ж трэбуе рашэнняі інжынера, а таксама як увядзіць кампайляр у існуючы код без настання проблем.

Ад спісу пунктав для мемаізацыі да автаматычнай мемаізацыі

Дзялёгі час саветы па падвышэнню карыстоўнасці React складаліся з короткага спісу інструментоў:

useMemo()
useCallback()
React.memo()

Компонент ператрыбутаваўся занадта часта, таму яго загарнулі. Вычысленне вярцалася даскладным, таму яго збераглі ў кэшы. Калебак выканаўся ў дзецячы компонент, таму яго стабілізавалі. Кожна з гэтых мераў была ручной мемаізацыяй, для якой трэбавалася арыйка залежнасцей.

Кампайляр React зменяе гэты стандарт. Версія 1.0 адзначаецца як стабільная, і рэкамендацыяя команды React для новага коду — дазволіць кампайляру здзейсніць мемаізацыю, у замест на ручныя викорыстанні useMemo і useCallback. Пераканаўцеся ў актуальных документах React, каб атрымаць найновейшыя прадактыкі ўжывання.

Суть можна выразыць ў адной фразе: кампайляр можа зробіць роботу самога React эфектывней, але ён не мае вплыву на роботу, якая адбываецца за межамі React.

Што на самай працэ кампайляр

У час будовы кампайляр аналізуе компаненты і хукі і дагаўляе мемаізацыю там, дзе, за яго аналізам, гэта є карысным. Возьмем компанент, які фільтруець спіс продуктав пры ўражанні:

function ProductList({ products }) {
  const visible = products.filter(
    product => product.inStock
  );

Фільтраванный масэвы потым праганяецца безпосередна да дзецінага компанента:

  return <List items={visible} />;
}

Даўжыню компіляцыі, развічальнік, які акцэнтавае увагу на выдатнасці, часта явным чынам кэшуе фільтр, так што List отрымае той самы аб’ект-адрэсу массива пакуль products не змяніцца:

const visible = useMemo(
  () => products.filter(
    product => product.inStock
  ),
  [products]
);

Калі компіляцыя ўвімкнута, такі код зазвычай праігноруецца. Компілятор сам вырахоўвае залежнасці, можа кэшаваць мяркавей, чым це робляць ручна напісаныя хукі, і не выкарыстоўвае правільна перыяктаваныя вам залежнасці. React называе гэта автаматычным кэшаваннем для компонентаў і хуків.

Адзначыце, протэму, межы ў гэтым апісанні: кожны элемент у лісте ёсць структурой React.

Ментальная модель: оптымізатор адрасавання

Дапамагае уявіць сабе компілятор як аб’ект, який працуе над двума типамі задач у React і адсекае ўсё зайвое:

React Compiler
                      │
          ┌───────────┴───────────┐
          ▼                       ▼
    Component work          Hook calculations
          │                       │
          ▼                       ▼
     memoization             memoization
          │                       │
          └───────────┬───────────┘
                      ▼
              fewer unnecessary
                 React updates

Меншая колькасць непатрэбных перыядражэнняў можа стаць справжнім прыбуткам. Аднак важлівай частю дыяграмы є тое, што яна не паказвае.

Медленныя бэкенды не ў межах яе можлівасцей

Разглядзім асінхронны компонент, які чакае на даны з API пры перыядражэнні панелі керування:

async function Dashboard() {
  const data = await fetch(
    "https://api.example.com/dashboard"
  );

Калі даны прыбываюць, яны перадаюцца інтерфейсу:

  return <DashboardUI data={data} />;
}

Якщо той канцэнтр патрабуе 800 мс, компілятор не зможа зменшыць гэты час да 50 мс. Ён можа спростыць пры ператварэнні дадзеных у інтерфейс у React, але не змусіць бэкенд адпавядаць быстрей. У вигляді часовай лініі:

Browser
   │
   ▼
React
   │
   ▼
API request ──────────► 800ms
   │
   ▼
Response
   │
   ▼
React render

Мемаізацыя выконвачваецца практычна абсалютна ў последнім кроцы. Якщо большая частка часу прабывае на чаканні сеті, вы оптымізаваеце не той слой; рашэнняя — глыбшыя запыткі, кэшаванне, меньшыя адпаведзіць или паралельнае запрашэнне дадзеных. Чыба адсепрація часу сеті ад часу кліента, пагляньце Diagnosing React Performance Issues Beyond the API Response Time.

JavaScript, які не трэба было дапраўляць

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

Initial page
     │
     ├── React
     ├── UI
     ├── Chart library
     ├── Editor
     └── Analytics SDK

Кампіляр не адключае жадных залежнасцей; кожны байт все равно завантажваецца, параскладываецца і выконвачаецца. Дапамагае раздзелэнне коду, напрыклад, завантажэнне экрана аналітыкі за патрэбай:

const Analytics = lazy(
  () => import("./Analytics")
);

Цей код запрашоўваецца толькі тады, калі функцыя насправды атрыбуецца, а суседнія межы Suspense паказваюць альтернатыўны варіант паказвання пакуль він завантажаецца. Цэя рашынка є часткай архітектуры пакетаў, і жадная мемазаванняе не можа яе заменіць.

Дзе выклікаюцца непарадныя наследкі

Частая ситуацыя: прыстрой запрацоўвае повольна, хтось увялічвае швальнасць компілятора, і каманда спадзяваецца на такі результат:

Slow app
   │
   ▼
React Compiler
   │
   ▼
Fast app

Гэта занадто проста. Повольнае запрацоўкі маюць калькі прычын, а компілятор падтрымлівае толькі адну з іх:

SLOW APP
                       │
       ┌───────────────┼───────────────┐
       ▼               ▼               ▼
    React work      Network          Browser
       │               │               │
       ▼               ▼               ▼
   Compiler        API/cache       JS/rendering
       │               │               │
       ▼               ▼               ▼
   Optimized       Engineer         Engineer

Компілятор — це толькі адна з інструментаў для падвышэння працэснасці, а не сама інструментальная сумка. Для рашэння проблем з задзеймленасцю сеті та витрамі браузера, такімі як адрабатка скрыптав і форматаванне, все рава патрэбны людзі.

Чы хаця быць выдалены існуючыя вызывы useMemo?

Не автаматычна. У нэвыканутага коду офіцыйны стандарт — дазволіць кампайляру выконваць мемаўванне. Для жыдучага коду React радзіць застаўляць чынны спосаб мемаўвання або адменаваць яго толькі пасля рэтельных тэставанняў. Прычына ціх рэкамендацый — паведанчасныя аспекты, а не толькі канцэрнавасць: значэнне, якое было мемаўвана і выкарыстоўваецца як залежнасць Effect, вялічы, калі гэты Effect зноў будзе выкананы, таму змена спосабу мемаўвання можа пацягнуць за сабой змены ў часе выканання паўнарадковых эфектаў.

Таму трэба стрымацца ад прагнення адразу выконаць такую чыстку ў всім кодбэсе:

useMemo      → DELETE
useCallback  → DELETE
React.memo   → DELETE

Безпечнейшы падход — поступовы, з пераканальнем на кожным кроцы:

Existing app
     │
     ▼
Enable compiler
     │
     ▼
Run tests
     │
     ▼
Profile
     │
     ▼
Remove unnecessary
manual memoization
carefully

Кампайляр створаны, каб у майбутнем зменшыць патрэбу ў ручным мемаўванні, а не каб за одну ноч заявіць, што ўсе існуючыя оптымізацыі неправильныя.

Кампайляр як пераканальнік якосці коду

Адзіныя перавага, якой падае меньшая увага: кампайляр включае этапы пераканальвання, створаныя на адпаведнасці з правіламі React, а його інтеграцыя з инструментамі лінтингу можа адказваць пра такія патэрны:

set-state-in-render
set-state-in-effect
unsafe ref access

React зазначае, што такія дыягнастыкі можу адкрыць багі, якія вже ўсё-такі існуюць у прыемлі. Паколькі кампайляр прахоўвае код, який наражае ў падазрэння його прыпускі, адзвешчанні таксама паказваюць, якія компоненты не оптымізаваны, таму гэта стае часткай ўседзённага цыклу адзвечання, а не проста плагінам для павышэння карыстоўнасці.

Спачатку аналізуйте, потым выберайце спосаб выправлення

Калі інтэрфейс здаецца медленным, перад тым, як вжываць будзь-які інструмент, здзейсніце вимеры, і нехай саме яны пакажуць прычыну:

SLOW UI
                 │
                 ▼
               PROFILE
                 │
        ┌────────┼────────┐
        ▼        ▼        ▼
      React    Network   Browser
       work      │        │
        │        │        │
        ▼        ▼        ▼
    Compiler   API/cache  JS/render
        │
        ▼
   Targeted fix

Потым падберіце спосаб выправлення, які будзе адпаведны таму, што паказвае інструмент аналізу:

  • Непатрэбныя перызначэння компонентаў у React: тут можа памагчы кампайляр React.
  • Медленны API: паспрабуйце паўнэчыць канец-пункт або стратэгію запрашання дадзеных.
  • Занадта большы ліст: адправляйце менш JavaScript за дапамою разбівання та скасавання залежнасцей.
  • Дорагі апдэты DOM: перазьвярзіце спосаб выканання рендэра, напрыклад, палячы дужыя лісты.
  • Важкі скрыпт трэцьяго сторонньага аплікацыі: адключыце яго, адкладзіце выкананне чы ўзградзіце яго.
  • Ключовыя выводы

    У старой модэлі было неабходна паведамляць React, што трэба запам’ятаваць; у новай вы можете пісаць правільны код на React і даваць кампайляру адпаведальнасць за большую частку роботы з рендэрам. Це падвышае значэнне адной навыку: ведаць, куды на самай працоўвае час.

    • Кампайляр оптымізуе тую роботу, якую разумее, тое ў значэнні рендэр React і вычыслення хуків.
    • Ён не можа зменшыць размер апасвячання API, прышвыдзіць запит да базы дадзеных, адключыць скрыпт трэцьяго сторонньага аплікацыі чы стиснуць адпрацоўванне 5 MB з’явы.
    • Ён не можа вываліць архітэктуру, якая стварае непатрэбную роботу ў всіх месцах.
    • У існуючам коде ўвядзіце яго, працаваць з ім, апрацаваць профіль i толькі пасля чаго адключыце ручную мемаізацыю.
    • Спрыяйце яго діагностицы як безкоштовным адказам пра наявнасць праваў React.

    Не запытваюце, чыякі кампайляр працуе, а лепш дзе практыка выдзейла свой час; самэ гэта і є метай кампайляра.