Оптимизация производительности dApp: RPC, кэширование, bundle size

Оптимизация dApp часто упирается в одну проблему: каждый UI-компонент выполняет собственный RPC-запрос, и никакой координации между ними нет. Десять компонентов порождают десять параллельных вызовов к провайдеру (Infura, Alchemy) с latency 100–300 ms. Пользователь наблюдает постепенное появление UI

Направления блокчейн-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1452
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1005
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1270
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    719
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1011

Оптимизация dApp часто упирается в одну проблему: каждый UI-компонент выполняет собственный RPC-запрос, и никакой координации между ними нет. Десять компонентов порождают десять параллельных вызовов к провайдеру (Infura, Alchemy) с latency 100–300 ms. Пользователь наблюдает постепенное появление UI с бесконечными спиннерами. Главная задача — объединить эти запросы и кэшировать ответы. Наш опыт — более 10 проектов по ускорению dApp, мы работаем с Web3 с 2017 года. Практика показывает: без вмешательства типичная DeFi-страница делает 50+ RPC-запросов в минуту, из которых 70% можно объединить в один. В одном из проектов (агрегатор ликвидности) после настройки multicall количество запросов сократилось в 8 раз, а TTI упал с 8 до 3 секунд. Экономия на инфраструктурных расходах превысила $3000 в год.

Проблемы, которые решаем

  • Чрезмерное количество RPC-запросов. Каждый вызов — это 100–300 ms задержки. Без батчинга приложение делает в 10 раз больше запросов, чем нужно.
  • Неоптимальный bundle size. Случайный импорт всего ethers вместо viem добавляет 200 KB gzipped.
  • Избыточные re-renders React. Компоненты перерендериваются при любом изменении аккаунта, даже если нужен только адрес.

Как multicall решает проблему задержек?

multicall3 — контракт, задеплоенный на большинстве EVM-сетей по адресу 0xcA11bde05977b3631167028862bE2a173976CA11. Он выполняет N view-вызовов в одном RPC-запросе. Multicall улучшает производительность в 10 раз по сравнению с отдельными вызовами, так как latency объединяется. Пример использования с wagmi v2:

import { useReadContracts } from 'wagmi' const { data } = useReadContracts({ contracts: [ { address: tokenA, abi: erc20Abi, functionName: 'balanceOf', args: [userAddress] }, { address: tokenB, abi: erc20Abi, functionName: 'balanceOf', args: [userAddress] }, { address: tokenC, abi: erc20Abi, functionName: 'balanceOf', args: [userAddress] }, ], }) 

wagmi v2 автоматически батчит вызовы через multicall3, если включена опция batch: { multicall: true }. Проверьте, что она активна — при отладке её часто отключают и забывают вернуть. Настройка занимает минуту, а сокращает количество запросов в 5–10 раз.

Почему code splitting так важен для dApp?

Компоненты работы с кошельком (WalletModal, Web3ReactManager) обращаются к window.ethereum при инициализации — их нельзя грузить на сервере. Dynamic import с ssr: false решает проблему:

const WalletModal = dynamic(() => import('@/components/WalletModal'), { ssr: false, loading: () => <Skeleton className="h-10 w-32" />, }) 

Это уменьшает первоначальный bundle на 30–50% и улучшает LCP. Для сравнения: code splitting даёт экономию трафика до 40% в крупных dApp.

Кэширование с TanStack Query

wagmi построен поверх TanStack Query. staleTime и gcTime напрямую влияют на количество RPC-запросов. Настройка по умолчанию часто неоптимальна:

const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 12_000, // 12 секунд – для balance данных gcTime: 5 * 60_000, // кэш живёт 5 минут retry: 2, retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30_000), }, }, }) 

Для статичных метаданных токенов выставляем staleTime: Infinity. Экономия — до 80% запросов без ущерба для актуальности.

Сравнение производительности до и после

Метрика До оптимизации После оптимизации
RPC-запросов 50 в минуту 5–10 в минуту
TTI 6 секунд 2–3 секунды
Bundle size 400 KB (gzipped) 200–250 KB (gzipped)
Тип данных Рекомендуемый staleTime Экономия запросов
Баланс токена 12 секунд 80%
Метаданные токена Infinity 100%
Цена (oracle) 30 секунд 90%

Процесс работы

  1. Аудит — профилируем React (React DevTools), анализируем bundle (Vite/Next.js analyzer), замеряем RPC-нагрузку через Network tab.
  2. Настройка multicall и батчинга — включаем batch: { multicall: true }, рефакторим вызовы под useReadContracts.
  3. Кэширование — подбираем staleTime под каждый тип данных.
  4. Code splitting — заменяем статические импорты на dynamic где нужно.
  5. Профилирование — проверяем re-render budget, добавляем useMemo и select.
  6. Документация и обучение — передаём конфиги и best practices.

Что входит в работу

  • Аудит производительности с отчётом.
  • Настройка multicall, TanStack Query, code splitting.
  • Оптимизация React rendering (selectors, memoization).
  • Профилирование и финальные замеры.
  • Документация изменений и рекомендации для поддержки.
  • Обучение команды (до 2 часов).

Сроки и стоимость

Работа занимает от 3 до 5 дней. Стоимость рассчитывается индивидуально — оценим проект после аудита. Свяжитесь с нами для консультации.

Типичные оптимизации в одном кейсе

Проект A: DeFi-агрегатор с 12 экранами. После настройки multicall количество RPC-запросов снизилось в 8 раз, TTI упал с 8 до 3 секунд, bundle уменьшился на 40%. Команда получила документацию и скрипты для мониторинга. Экономия на инфраструктурных расходах достигла 70% (более $3000 в год).

Получите консультацию по оптимизации вашего dApp. Наши инженеры готовы провести аудит и предложить конкретные улучшения. Оставьте заявку на бесплатный анализ — мы покажем, какие метрики можно улучшить.