Головна / Статті / Пояснення часткової попередньої обробки та одночасної обробки

Пояснення часткової попередньої обробки та одночасної обробки

Дізнайтеся, як функція часткової попередньої обробки в Next.js та функція паралельної обробки в React вирішують проблему повільної роботи додатків, дозволяючи цим фреймворкам планувати та виконувати завдання поетапно, замість того щоб розглядати процес обробки як єдину блокуючу одиницю.

1346 слів

Сучасні практики оптимізації продуктивності React та Next.js постійно повертаються до одного й того ж висновку: саме примусове поводження всієї сторінки чи всього процесу відображення як єдиного, неперервного цілого є причиною повільної роботи додатків. Два підходи вирішують цю проблему з різних боків — часткове попереднє відображення, яке дозволяє окремому маршруту Next.js поєднувати статичний та динамічний контент, та одночасне відображення, яке дозволяє React переривати та переупорядковувати операції в браузері. Разом вони демонструють закономірність, яку варто зрозуміти: покращення продуктивності все частіше досягається не шляхом написання „швидшого“ коду, а завдяки тому, що фреймворк може більш розумно планувати та виконувати завдання.

Старий вибір між повним чи жодним відображенням

Протягом тривалого часу у Next.js існувало рівно два режими відображення, з яких можна було обирати:

  • Статична генерація (SSG) — сторінки швидко завантажуються, оскільки вони створюються заздалегідь, але їхній вміст стає застарілим до наступної переробки.
  • Рендеринг з боку сервера (SSR) — вміст завжди є актуальним, але кожен запит змушений чекати на найповільніші дані, перш ніж щось буде надіслано назад.

Проблема полягає у тому, що більшість реальних сторінок не підходять чітко ні до однієї з цих категорій. Сторінка продукту, наприклад, переважно є статичною — макет, навігація та маркетинговий текст не змінюються з кожним запитом — але вона також містить кілька справді динамічних елементів, таких як індикатор кошика чи лайв-лічильник запасів. Рендеринг усієї сторінки за допомогою SSR лише для того, щоб один невеликий елемент залишався актуальним, означає оплату повної вартості серверного рендерингу для контенту, який цього не потребує.

Дозвіл одному маршруту бути водночас статичним та динамічним

Часткова попередня обробка (PPR) існує саме для подолання цієї прогалини. Вона дозволяє одному маршруту негайно надати статичну основу, тоді як динамічні фрагменти всередині неї передаються у режимі потоку як тільки їхні дані готові — без окремих сторінок та без необхідності постійного перемикання між getStaticProps та getServerSideProps.

// app/product/[id]/page.tsx
import { Suspense } from 'react';
import ProductShell from '@/components/ProductShell';
import LiveInventory from '@/components/LiveInventory';

export default function ProductPage({ params }: { params: { id: string } }) {
  return (
    <ProductShell productId={params.id}>
      {/* static instantly, no waiting on the network */}
      <Suspense fallback={<InventorySkeleton />}>
        {/* streamed in once the dynamic data resolves */}
        <LiveInventory productId={params.id} />
      </Suspense>
    </ProductShell>
  );
}

Механізм полягає у межах Suspense. Усе, що знаходиться за межами цих меж, попередньо обробляється під час створення проекту та негайно надається; усе, що знаходиться всередині, обчислюється та передається у режимі потоку під час запиту. Ось вся суть цього підходу: один файл, один маршрут, співіснування двох стратегій обробки.

Цей підхід приносить кілька конкретних переваг. Час отримання першого байту скорочується, оскільки статична оболонка надсилається безпосередньо з сервера, а не обчислюється для кожного запиту. Також немає потреби у стані завантаження всієї сторінки — відвідувачі одразу бачать значущі, статичні частини сторінки, а менші динамічні елементи додаються після їх обробки. Крім того, розумове навантаження менше порівняно з підтримкою окремих статичних та серверно-генерованих сторінок, адже працюється з одним маршрутом та одним файлом, який просто поєднує різні стратегії. Команда Next.js описує мету як отримання переваг як статичного, так і динамічного рендерингу без звичайних архітектурних компромісів.

Кілька практичних рекомендацій допомагають зробити PPR ефективним у продакшені. Тримайте межі Suspense вузькими лише навколо тих частин, які справді є динамічними — обгортання занадто великої кількості контенту псує сенс попередньої обробки. Зберігайте фолбек-скелети легкими, адже ці фолбеки самі є частиною статично обробленої оболонки. Якщо ви використовуєте TypeScript, визначайте чіткі контракти властивостей між статичною оболонкою та компонентами, які надходять стрімом, щоб обидві частини залишалися синхронними під час їх розвитку. А під час тестування обмежуйте швидкість з’єднання до рівня повільного 3G у інструментах розробки браузера — переваги PPR стають значно очевиднішими за реалістичних мережевих умов, ніж при швидкому локальному з’єднанні.

Якщо ваша команда використовує Next.js 14 або новішу версію, варто спробувати PPR для окремого маршруту перед тим, як застосувати його у всій програмі. Це не маркетинговий термін — це стратегія відображення, яка нарешті відповідає реальній поведінці сторінок: частково статичними, частково динамічними одночасно.

Розширення цієї ідеї на клієнтське відображення

Часткове попереднє відображення вирішує проблему розділення на статичне та динамічне на рівні сервера та мережі. Конкурентне відображення, запроваджене у React 18 та дороблене у React 19, вирішує аналогічну проблему всередині браузера: замість того, щоб обирати між „відобразити все зараз“ та „не відображати нічого поки“, React може негайно відобразити деякі елементи, а інші залишити на потім.

До React 18 відображення контенту відбувалося синхронно та блокуюче. Одне оновлення стану запускало повторне відображення, яке завершувалося незалежно від усього — навіть якщо це означало зупинку прокрутки чи введення даних під час обробки всього дерева стану React.

Функція паралельного відображення змінює цю поведінку. Тепер React може призупинити процес відображення на певному етапі, надати пріоритет терміновим оновленням, таким як введення тексту чи кліки, перед менш терміновими, наприклад фільтрацією довгого списку, а також відкинути поточну роботу, якщо новіше оновлення робить її непотрібною. Важливо те, що це не новий API, який потрібно вивчати з нуля — це інша модель планування, яка працює під керуванням гаків, які ви вже використовуєте.

Гаки, які дозволяють використовувати паралельне планування

useTransition дозволяє позначити оновлення стану як неважливе, щоб React міг зберегти реактивність інтерфейсу під час обробки цього оновлення на фоні.

function ProductSearch() {
  const [query, setQuery] = useState("");
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  function handleChange(e) {
    const value = e.target.value;
    setQuery(value); // urgent — keep input snappy

    startTransition(() => {
      // non-urgent — can be interrupted
      setResults(filterProducts(value));
    });
  }

  return (
    <>
      <input value={query} onChange={handleChange} />
      {isPending && <span className="text-gray-400">Updating…</span>}
      <ResultsList items={results} />
    </>
  );
}

Завдяки цій схемі введення тексту у поле пошуку залишається плавним навіть під час фільтрації тисяч елементів на сервері.

Suspense виконує подібну функцію стрімінгу на клієнті, як і в PPR на сервері: замість того, щоб блокувати всю сторінку під час завантаження даних, він дозволяє окремим елементам інтерфейсу оброблятися незалежно. У поєднанні з Next.js App Router це також дозволяє використовувати серверні компоненти, які поступово вставляються у сторінку, замість того, щоб затримувати повне завантаження.

useDeferredValue вирішує схожу, але окрему проблему: дорогі перерендеринги, спричинені значеннями з пропсів чи контексту, а не з локального стану компонента. Він дозволяє React відкласти перерахунок цих дорогих частин до моменту, коли у нього з’явиться вільний час.

Для команд, які працюють з React, Next.js, TypeScript, Redux та Tailwind CSS, ця модель планування має значення не лише для окремих хуків — нові асинхронні патерни в Redux Toolkit та спосіб функціонування Next.js Server Actions у глибині системи обидва ґрунтуються на тому самому основному конкурентному плануванні, яке тепер надає React. Конкурентність — це не щось, що можна увімкнути безпосередньо; це можливість, яку React застосовує автоматично, як тільки ваші компоненти структуровані таким чином, що дозволяє переривати та відновлювати їхнє відображення.

Що потрібно пам’ятати

У обох техніках основний урок залишається однаковим: саме розгляд цілої сторінки або цілого результату відрендерингу як єдиного недільмового елемента спричиняє повільну роботу, а не обов’язково неефективний код. Конкурентний відрендеринг — це не про написання швидшого коду, а про розумніше планування виконання коду, який у вас вже є. На практиці це означає відкладання нетермінових оновлень стану за допомогою useTransition, потокове отримання даних за допомогою Suspense та тестування на пристроях з нижчими характеристиками, адже саме там переваги конкурентності є найбільш помітними. У поєднанні з частковим попереднім відрендерингом на серверній стороні ці інструменти дозволяють окремому маршруту чи дереву компонентів миттєво надавати статичний контент, тоді як динамічний контент потоково надходить лише тоді, коли це можливо — це найкраще з обох світів відрендерингу, без необхідності перебудови вашої архітектури навколо будь-якого з крайнощів.

Пов’язана література

  • Inside TypeScript 7's Go Rewrite: Speed Gains Without Code Changes — Дізнайтеся, як компілятор TypeScript 7 на основі Go забезпечує у 8–12 разів швидшу збірку коду, чому ефективна ця архітектурна зміна та як безпечно оновлювати існуючі проекти.
  • React 19.2 SSR Primitives: Activity, cacheSignal, and PPR Explained — Дізнайтеся, як новий компонент Activity, cacheSignal та функція часткової попередньої обробки React 19.2 надають розробникам прямий контроль над продуктивністю серверної обробки.
  • Навичка AGENTS.md від Vercel навчає AI-асистентів 70 кращих практик React — детальний огляд навички agent react-best-practices від Vercel, який показує, як вона вбудовує 70 перевірених у реальних проектах правил React безпосередньо в код, створений штучним інтелектом.